예제 #1
0
 public virtual Reply GetReply()
 {
     Reply r = new Reply();
     r.t = ReplyType.ReplyNone;
     return r;
 }
예제 #2
0
        private void Worker()
        {
            Action<Reply> SendReply = (Reply r) =>
            {
                lock (this)
                {
                    this.replies.AddLast(r);
                }
            };
            Action CloseSerial = () =>
            {
                try
                {
                    if ((this.serialHandle != null) && this.serialHandle.IsOpen)
                    {
                        this.serialHandle.Close();
                    }
                }
                catch (Exception)
                {
                }
                this.serialHandle = null;
            };
            Action<string> ConnectionError = (string s) =>
            {
                CloseSerial();
                Reply r = new Reply();
                r.t = ReplyType.ReplyError;
                r.errorCode = s;
                SendReply(r);
            };
            Action<byte[], int> SendSerialCommand = (byte[] data, int size) =>
            {
                if (this.serialHandle == null)
                {
                    return;
                }
                try
                {
                    this.serialHandle.Write(data, 0, size);
                    int ok = this.serialHandle.ReadByte();
                    if (ok != 'K')
                    {
                        ConnectionError("Protocol error when sending command " + data[0] + ", got " + ok);
                    }
                }
                catch (System.TimeoutException)
                {
                    ConnectionError("Timeout error when sending command " + data[0]);
                }
                catch (Exception e)
                {
                    ConnectionError("Communications error when sending command " + data[0] + ": " + e.Message);
                }
            };
            Action<byte[], int> ReadSerialBytes = (byte[] data, int size) =>
            {
                if (this.serialHandle == null)
                {
                    return;
                }
                try
                {
                    int count = 0, offset = 0;

                    while (count < size)
                    {
                        int now = this.serialHandle.Read(data, offset, size - count);
                        if (now <= 0)
                        {
                            ConnectionError("Protocol error when reading " + size + " bytes: got " + count + " and " + now);
                        }
                        count += now;
                        offset += now;
                    }
                }
                catch (System.TimeoutException)
                {
                    ConnectionError("Timeout error when reading " + size + " bytes");
                }
                catch (Exception e)
                {
                    ConnectionError("Communications error when reading " + size + " bytes: " + e.Message);
                }
            };
            Action<int> SendDisplay = (int d) =>
            {
                byte[] b = new byte[2];
                b[0] = (byte)'D';
                b[1] = (byte)d;
                SendSerialCommand(b, 2);
            };
            Action PostConnection = () =>
            {
                byte[] bytesOut = new byte[16];
                byte[] bytesIn = new byte[16];

                // Activities carried out when a connection is established
                // set display to 0xc
                SendDisplay(0x10);
                SendDisplay(0xc);

                // request current colour
                Reply r = new Reply();
                bytesOut[0] = (byte)'c'; // request current colour
                SendSerialCommand(bytesOut, 1);
                if (this.serialHandle == null) return;
                ReadSerialBytes(bytesIn, 3);
                if (this.serialHandle == null) return;
                // Send "connected" message as connection seems ok
                r.red = (int)bytesIn[0];
                r.green = (int)bytesIn[1];
                r.blue = (int)bytesIn[2];
                r.t = ReplyType.ReplyConnected;
                SendReply(r);

                // Download programs
                for (int i = 0; i < num_programs; i++)
                {
                    bytesOut[0] = (byte)'L'; // load program from EEPROM
                    bytesOut[1] = (byte)i;
                    SendSerialCommand(bytesOut, 2);
                    if (this.serialHandle == null) return;
                    bytesOut[0] = (byte)'m'; // download program via serial line
                    SendSerialCommand(bytesOut, 1);
                    if (this.serialHandle == null) return;
                    r.program_bytes = new byte[program_size];
                    r.program_number = i;
                    ReadSerialBytes(r.program_bytes, program_size);
                    if (this.serialHandle == null) return;
                    r.t = ReplyType.ReplyProgram;
                    SendReply(r);
                }
            };

            Command colour = new Command();
            LinkedList<Command> sequential = new LinkedList<Command>();
            bool get_colour = false;
            while (true)
            {
                colour.t = CommandType.CommandNone;
                get_colour = false;
                sequential.Clear();

                // Await messages
                lock (this)
                {
                    if (commands.Count == 0)
                    {
                        try
                        {
                            Monitor.Wait(this);
                        }
                        catch (Exception) { }
                    }
                    while (commands.Count != 0)
                    {
                        Command cmd = commands.First();
                        commands.RemoveFirst();
                        switch (cmd.t)
                        {
                            case CommandType.CommandSetColour:
                                // Only keep the most recent colour command
                                colour = cmd;
                                break;
                            case CommandType.CommandGetColour:
                                // Done after SetColour
                                get_colour = true;
                                break;
                            case CommandType.CommandExit:
                                // exit takes priority over everything else: immediate exit
                                CloseSerial();
                                return;
                            default:
                                // All other commands are processed in sequence
                                sequential.AddLast (cmd);
                                break;
                        }
                    }
                }
                // Process commands apart from colour
                while (sequential.Count != 0)
                {
                    Command cmd = sequential.First();
                    sequential.RemoveFirst();

                    switch (cmd.t)
                    {
                        case CommandType.CommandConnect:
                            CloseSerial();
                            try
                            {
                                this.serialHandle = new SerialPort(cmd.portName, 19200);
                                this.serialHandle.ReadTimeout = timeout;
                                this.serialHandle.WriteTimeout = timeout;
                                this.serialHandle.Open();
                            }
                            catch (Exception e)
                            {
                                ConnectionError("Connection to " + cmd.portName + " failed with error: " + e.Message);
                            }
                            if (this.serialHandle != null)
                            {
                                // send some '\0' bytes before starting it
                                const int leadin_size = 6;
                                byte[] initBytesOut = new byte[leadin_size];
                                initBytesOut[leadin_size - 1] = (byte)'Q';

                                int attempts = 3;
                                while (attempts > 0)
                                {
                                    try
                                    {
                                        this.serialHandle.Write(initBytesOut, 0, leadin_size);
                                    }
                                    catch (Exception)
                                    {
                                        ConnectionError("Write error during setup");
                                        break;
                                    }
                                    try
                                    {
                                        this.serialHandle.ReadTo("K");
                                        try
                                        {
                                            // This read is expected to timeout.
                                            // Just flushes extra stuff on the input
                                            this.serialHandle.ReadTo("Z");
                                        }
                                        catch (Exception)
                                        {
                                        }
                                        break;
                                    }
                                    catch (TimeoutException)
                                    {
                                        // try again unless final attempt
                                        attempts--;
                                        if (attempts <= 0)
                                        {
                                            ConnectionError("Timeout during connection: no valid response");
                                            break;
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        ConnectionError("Read error during setup");
                                        break;
                                    }
                                }

                                PostConnection();
                            }
                            else
                            {
                                CloseSerial();
                            }
                            break;
                        case CommandType.CommandSetDisplay:
                            {
                                Reply r = new Reply();
                                r.t = ReplyType.ReplyMsg;
                                r.errorCode = "Setting display " + cmd.value;
                                SendReply(r);
                                SendDisplay(cmd.value);
                            }
                            break;
                        case CommandType.CommandRunEEPROMProgram:
                            {
                                byte[] bytesOut = new byte[2];
                                bytesOut[0] = (byte)'L'; // load from EEPROM
                                bytesOut[1] = (byte)cmd.value; // program number
                                SendSerialCommand(bytesOut, 2);
                                bytesOut[0] = (byte)'R'; // run
                                SendSerialCommand(bytesOut, 1);
                                Reply r = new Reply();
                                r.t = ReplyType.ReplyMsg;
                                r.errorCode = "Running program " + cmd.value;
                                SendReply(r);
                            }
                            break;
                        case CommandType.CommandRunTemporaryProgram:
                            {
                                byte[] bytesOut = new byte[Comms.program_size + 1];
                                bytesOut[0] = (byte)'M'; // upload program via serial line (PC to Arduino)
                                for (int i = 0; i < Comms.program_size; i++)
                                {
                                    bytesOut[i + 1] = cmd.program_bytes[i];
                                }
                                SendSerialCommand(bytesOut, Comms.program_size + 1);
                                bytesOut[0] = (byte)'R'; // run
                                SendSerialCommand(bytesOut, 1);
                                Reply r = new Reply();
                                r.t = ReplyType.ReplyMsg;
                                r.errorCode = "Running program from editor";
                                SendReply(r);
                            }
                            break;
                        case CommandType.CommandSaveEEPROMProgram:
                            {
                                Reply r = new Reply();
                                r.t = ReplyType.ReplyMsg;
                                r.errorCode = "Writing program " + cmd.program_number + " to EEPROM";
                                SendReply(r);

                                byte[] bytesOut = new byte[Comms.program_size + 1];
                                bytesOut[0] = (byte)'M'; // upload program via serial line (PC to Arduino)
                                for (int i = 0; i < Comms.program_size; i++)
                                {
                                    bytesOut[i + 1] = cmd.program_bytes[i];
                                }
                                SendSerialCommand(bytesOut, Comms.program_size + 1);
                                bytesOut[0] = (byte)'S'; // save to EEPROM
                                bytesOut[1] = (byte)cmd.program_number;
                                if (this.serialHandle != null)
                                {
                                    this.serialHandle.ReadTimeout = eeprom_write_timeout;
                                    SendSerialCommand(bytesOut, 2);
                                }
                                if (this.serialHandle != null)
                                {
                                    this.serialHandle.ReadTimeout = timeout;
                                }
                                bytesOut[0] = (byte)'L'; // load program from EEPROM (readback)
                                bytesOut[1] = (byte)cmd.program_number;
                                SendSerialCommand(bytesOut, 2);
                                bytesOut[0] = (byte)'m'; // download program via serial line (readback)
                                SendSerialCommand(bytesOut, 1);
                                if (this.serialHandle != null)
                                {
                                    r = new Reply();
                                    r.program_bytes = new byte[Comms.program_size];
                                    r.program_number = cmd.program_number;
                                    ReadSerialBytes(r.program_bytes, Comms.program_size);
                                    r.t = ReplyType.ReplyProgram;
                                    SendReply(r);
                                }
                                if (this.serialHandle != null)
                                {
                                    r = new Reply();
                                    r.t = ReplyType.ReplyMsg;
                                    r.errorCode = "Done";
                                    SendReply(r);
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
                // Process colour command
                if (colour.t != CommandType.CommandNone)
                {
                    byte[] b = new byte[4];
                    b[0] = (byte) 'C';
                    b[1] = (byte) colour.red;
                    b[2] = (byte) colour.green;
                    b[3] = (byte) colour.blue;
                    SendSerialCommand (b, 4);
                }
                if (get_colour)
                {
                    get_colour = false;
                    byte[] bytesOut = new byte[1];
                    bytesOut[0] = (byte)'c'; // request current colour
                    SendSerialCommand(bytesOut, 1);
                    byte[] bytesIn = new byte[3];
                    ReadSerialBytes(bytesIn, 3);
                    Reply r = new Reply();
                    r.t = ReplyType.ReplyProgram;
                    r.red = (int)bytesIn[0];
                    r.green = (int)bytesIn[1];
                    r.blue = (int)bytesIn[2];
                    r.t = ReplyType.ReplyGotColour;
                    SendReply(r);
                }
            }
        }
예제 #3
0
 public override Reply GetReply()
 {
     Reply r;
     lock (this)
     {
         if (this.replies.Count != 0)
         {
             r = this.replies.First();
             this.replies.RemoveFirst();
         }
         else
         {
             r = new Reply();
             r.t = ReplyType.ReplyNone;
         }
     }
     return r;
 }
예제 #4
0
 public void SimulatorSendReply(Reply r)
 {
     this.replies.AddLast(r);
 }
예제 #5
0
        public void RefreshSimulation(SimulatorComms comms)
        {
            if (this.simulated_program != null)
            {
                long ticks = DateTime.Now.Ticks - this.start_time;
                long milliseconds = ticks / TimeSpan.TicksPerMillisecond;
                int sim_time = (int)milliseconds;
                int size = this.simulated_program.contents.Count();

                if ((this.program_time + 120000) < sim_time)
                {
                    // clock skew - reset the program
                    this.program_time = 0;
                    this.start_time = DateTime.Now.Ticks;
                    this.program_counter = 0;
                }

                while (this.program_time < sim_time)
                {
                    // run forwards until the program time matches the simulator time
                    if (this.program_counter >= size)
                    {
                        this.program_counter = 0; // loop at end of program
                    }
                    Instruction inst = this.simulated_program.contents[this.program_counter];
                    int end_time = inst.getTime() + this.program_time;
                    bool commit = true;

                    switch (inst.t)
                    {
                        case InstructionType.InstructionSetDisplay:
                            this.setDisplay(inst.value);
                            break;
                        case InstructionType.InstructionTransition:
                            if (end_time < sim_time)
                            {
                                // Running behind. Apply this instruction immediately.
                                this.r = inst.r;
                                this.g = inst.g;
                                this.b = inst.b;
                                this.setColour(this.r, this.g, this.b);
                            }
                            else
                            {
                                // Transition
                                int rS = this.r, gS = this.g, bS = this.b;
                                int rT = inst.r, gT = inst.g, bT = inst.b;
                                int tD = (int)(sim_time - this.program_time);
                                int tI = (int)(end_time - this.program_time);
                                byte r = linear(rS, rT, tD, tI);
                                byte g = linear(gS, gT, tD, tI);
                                byte b = linear(bS, bT, tD, tI);
                                this.setColour(r, g, b);
                                commit = false;
                            }
                            break;
                        default:
                            break;
                    }
                    if (commit)
                    {
                        // Go to next instruction
                        this.program_counter++;
                        this.program_time = end_time;
                    }
                    else
                    {
                        // Need to wait for this instruction to complete
                        this.programState.Text = "Inst " + (this.program_counter + 1) + " of " + size + ": "
                            + inst.ToString();
                        break;
                    }
                }
            }

            while (true)
            {
                Command c = comms.SimulatorGetCommand();
                Reply r;
                switch (c.t)
                {
                    case CommandType.CommandNone:
                        return;
                    case CommandType.CommandConnect:
                        r = new Reply();
                        r.red = r.green = r.blue = 0x20;
                        r.t = ReplyType.ReplyConnected;
                        comms.SimulatorSendReply(r);
                        for (int i = 0; i < Comms.num_programs; i++)
                        {
                            r = new Reply();
                            r.program_number = i;
                            r.program_bytes = readProgram(i);

                            r.t = ReplyType.ReplyProgram;
                            comms.SimulatorSendReply(r);
                        }

                        r = new Reply();
                        r.errorCode = "Simulated mode";
                        r.t = ReplyType.ReplyMsg;
                        comms.SimulatorSendReply(r);
                        this.display.Text = "C";
                        this.Show();
                        break;
                    case CommandType.CommandSetColour:
                        this.simulated_program = null;
                        this.setColour(c.red, c.green, c.blue);
                        this.r = c.red;
                        this.g = c.green;
                        this.b = c.blue;
                        this.programState.Text = "";
                        break;
                    case CommandType.CommandGetColour:
                        this.simulated_program = null;
                        r = new Reply();
                        r.red = this.r; r.green = this.g; r.blue = this.b;
                        r.t = ReplyType.ReplyGotColour;
                        comms.SimulatorSendReply(r);
                        break;
                    case CommandType.CommandSetDisplay:
                        this.simulated_program = null;
                        setDisplay(c.value);
                        this.programState.Text = "";
                        break;
                    case CommandType.CommandExit:
                        this.simulated_program = null;
                        break;
                    case CommandType.CommandRunEEPROMProgram:
                        this.simulated_program = new InstructionList(readProgram(c.value));
                        startProgram(comms, "" + c.value);
                        break;
                    case CommandType.CommandRunTemporaryProgram:
                        this.simulated_program = new InstructionList(c.program_bytes);
                        startProgram(comms, "(temporary)");
                        break;
                    case CommandType.CommandSaveEEPROMProgram:
                        writeProgram(c.program_number, c.program_bytes);
                        r = new Reply();
                        r.t = ReplyType.ReplyProgram;
                        r.program_number = c.program_number;
                        r.program_bytes = readProgram(c.program_number);
                        comms.SimulatorSendReply(r);
                        r = new Reply();
                        r.errorCode = "Written to simulated EEPROM";
                        r.t = ReplyType.ReplyMsg;
                        comms.SimulatorSendReply(r);
                        break;
                }
            }
        }
예제 #6
0
 private void startProgram(SimulatorComms comms, string name)
 {
     Reply r;
     this.start_time = DateTime.Now.Ticks;
     this.program_time = 0;
     this.program_counter = 0;
     if (this.simulated_program.contents.Count() == 0)
     {
         r = new Reply();
         r.errorCode = "Program " + name + " contains no instructions.";
         r.t = ReplyType.ReplyMsg;
         comms.SimulatorSendReply(r);
         this.simulated_program = null;
     }
     else if (this.simulated_program.end_time <= 0)
     {
         r = new Reply();
         r.errorCode = "Program " + name + " has no running time.";
         r.t = ReplyType.ReplyMsg;
         comms.SimulatorSendReply(r);
         this.simulated_program = null;
     }
     else
     {
         r = new Reply();
         r.errorCode = "Program " + name + " simulating...";
         r.t = ReplyType.ReplyMsg;
         comms.SimulatorSendReply(r);
     }
     this.programState.Text = r.errorCode;
 }