Пример #1
0
        /// <summary>
        /// Objects of this class spend most of their execution time in this method.  It simply waits asynchronously (control
        /// is returned to the constructor and then returned here on an interrupt) for data.  When data is read it is packaged
        /// and sent to the event dispatcher.  
        /// </summary>
        /// <returns></returns>
        /// <exception cref="ReceiverExceptions">Thrown when the EOF is reached on the read stream (contains an 
        /// EndOfStreamException</exception>
        public async Task run()
        {
            while (goState > 0)
            {
                var ret = string.Empty;
                var buffer = new char[1]; // Not the most efficient...
                while (!ret.Contains("\n") && (!ret.Contains("\r")))
                {
                    var charsRead = await textReader.ReadAsync(buffer, 0, 1);
                    if (charsRead == 0)
                    {
                        EndOfStreamException eose = new EndOfStreamException();
                        ReceiverExceptions re = new ReceiverExceptions(this,"End of stream reached on serial port.",true,eose);
                        dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re, re.fatal,
                            this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
                        throw re;
                    }
                    ret += buffer[0];
                }

                if (ret.Length > 1)
                {
                    dispatcher.enqueueEvent(new RealTimeEvents.UnparsedMessage(ret,
                        this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
                }
            }
            goState = -1;
        }
Пример #2
0
        /// <summary>
        /// Public constructor for the Receiver class.
        /// </summary>
        /// <param name="serialPort">The serial port object to which the receiver is connected</param>
        /// <param name="portName">The name of the port (i.e. COM1, COM2, etc.)</param>
        /// <param name="dispatcher">The event queue dispatcher where events generated by this class are sent</param>
        /// <remarks>
        /// After opening the port, the constructor calls the init() method which determines whether the hardware connect
        /// is, in fact, a VEMCO reciever and then proceeds to configure it.  After returning, the constructor then instructs
        /// the receiver to start sending "Real Time" data.  Finally the run() method is called and the objects stays in
        /// the run method until it shutdown() is called.  With the exception of whether the class in run()ing or not, no state
        /// is maintained by the class.
        /// </remarks>
        public Receiver(SerialPort serialPort, String portName, Dispatcher dispatcher)
        {
            Dictionary<int, string> configFiles = new Dictionary<int, string>();
            this.TTL = DEFAULT_TTL;
            this.serialPort = serialPort;
            this.portName = portName;
            this.dispatcher = dispatcher;

            
            
            serialPort.Open();
            encoder = null;
            init();
            if (encoder != null)
            {
                
                this.textReader = new StreamReader(serialPort.BaseStream, serialPort.Encoding);
                Object[] r = {"0"};
                write("RTMPROFILE", r);
                write("START");
                Thread.Sleep(500);
                while (serialPort.BytesToRead > 0)
                {
                    dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("Read: " + serialPort.ReadExisting(),
                        this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
                }
                run();
                dispatcher.enqueueEvent(new RealTimeEvents.NewReceiver(this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
            }
            else
            {
                ReceiverExceptions re = new ReceiverExceptions(this, "(FATAL) Failed to configure encoder during init().", true);
                dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re,re.fatal, 
                    this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
                serialPort.Close();
                throw re;
            }
        }
Пример #3
0
        /// <summary>
        /// Called by the constructor to determine whether a VEMCO receiver is attached (vs another kind of 
        /// serial device), what the firmware is and which configuration file should be used.
        /// </summary>
        /// <remarks>
        /// Because one of the goals of this method is to determine the firmware (and corresponding configuration file),
        /// for the most part we must try both "default" commands and all those available in the configuration files.
        /// One assumption here is that future changes to protocol's INFO and discovery methods will not interfere with
        /// the operation of prior receivers.  And although we can take some care to provide as much flexibility for
        /// changes in the protocol, there are clearly some limits.  For example, we cannot anticipate a change to
        /// a binary format.
        /// 
        /// The init() method first attempts to "discover" the connected receiver.  Generally a receiver will not respond
        /// to commands that are not prefaced by the serial number, etc.  Since we do not have the serial number prior to 
        /// running this method, we must use the VEMCO's broadcast and discover commands.
        /// 
        /// Next the method issues INFO commands in order to scrape out the firmware version.  We assume here that the 
        /// manufacturer's protocol will remain stable within a firmware version.  Also note that so long as the protocol
        /// itself does not change, there is no need for additional configuration files.  
        /// 
        /// Assuming that these two tasks are completed without bailing, then init() command completes and returns
        /// control to the constructor.
        /// </remarks>
        /// <exception cref="ReceiverExceptions">Thrown when either the discovery
        /// or info phase is not able to acquire the needed information</exception>
        public void init()
        {
            Dictionary<Double, List<dynamic>> discoveryMethods = new Dictionary<Double, List<dynamic>>();
            Dictionary<Double, String> infoMethods = new Dictionary<Double, String>();
            String discoveryReturns = "";
            
            var jsonParser = new JsonParser() { CamelizeProperties = false };

            foreach (string filename in System.IO.Directory.GetFiles(VR2C_COMMAND_FOLDER))
            {
                dynamic config = jsonParser.Parse(System.IO.File.ReadAllText(filename));
                var dc = config.discovery_commands;
                var fwver = config.firmware_version;
                try
                {
                    infoMethods.Add(fwver, (string)config.encoder["INFO"]);
                }
                catch(Exception e)
                {
                    ReceiverExceptions re = new ReceiverExceptions(this, "INFO command not found in " + 
                        "configuration file: " + filename + ". This is normally not fatal on its own but " +
                        "indicates a serious problem with the format/content of the config file.",
                        false,e);
                    dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re.fatal, re.ToString(),
                        this, this.portName, null, null, null));
                }

                try
                {
                    discoveryMethods.Add(((int)fwver), dc);
                }
                catch (Exception e)
                {
                    ReceiverExceptions re = new ReceiverExceptions(this, "Discovery commands not found in " +
                        "configuration file: " + filename + ". This is normally not fatal on its own but " +
                        "indicates a serious problem with the format/content of the config file.",
                        false, e);
                    dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re.fatal, re.text,
                        this, this.portName, null, null, null));
                }
                

            }



            List<dynamic> default_discovery = new List<dynamic>();
            default_discovery.Add("*BROADC.A#ST,QUIT");
            default_discovery.Add("*BROADC.A#ST,DISCOVERY");
            default_discovery.Add("*DISCOV.E#RY,DISCOVERY");
            discoveryMethods.Add(-1, default_discovery);

            int discovery_attempts = 0;
            serialPort.ReadExisting();
            while (serialPort.BytesToRead <= 0 && discovery_attempts < 5)
            {
                write_wait = (discovery_attempts + 1) * 100;
                foreach (List<dynamic> l in discoveryMethods.Values)
                {
                    foreach(var command in l) {
                        _write(command);
                    }
                }
                discovery_attempts++;
            }
            if (discovery_attempts >= 5)
            {
                ReceiverExceptions re = new ReceiverExceptions(this, "Not able to discover VEMCO receiver attached on this port.", true);
                dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re,re.fatal, 
                    this, this.portName, null,null, null));
                serialPort.Close();
                throw re;
            }

            while (serialPort.BytesToRead > 0)
            {
                discoveryReturns = serialPort.ReadExisting();
            }
            

            string commandPreamble = discoveryReturns.Substring(0, 12) + ",";
            this.VEMCO_SerialNumber = discoveryReturns.Substring(1,6);
            dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("command preamble: " + discoveryReturns.Substring(0,12) + ",",
                this, this.portName, this.VEMCO_SerialNumber, null, null));
            dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("read: " + discoveryReturns,
                this, this.portName, this.VEMCO_SerialNumber, null, null));

            infoMethods.Add(-1, commandPreamble + "INFO");
            int info_attempts = 0;
            serialPort.ReadExisting();
            Boolean gotINFO = false;
            String infoReturns = "";
            int read_attempts = 0;

            while (!gotINFO && read_attempts < 5)
            {
                info_attempts = 0;
                serialPort.ReadExisting();
                while (serialPort.BytesToRead <= 0 && info_attempts < 5)
                {
                    foreach (String infoc in infoMethods.Values)
                    {
                        dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("(receiver note) attempting INFO command with " + infoc,
                            this, this.portName, this.VEMCO_SerialNumber, null, null));
                        _write(infoc);
                        Thread.Sleep(500);
                    }
                    info_attempts++;
                }

                while (serialPort.BytesToRead > 0 && !(infoReturns.Contains(crlf[0]) || infoReturns.Contains(crlf[1])))
                {
                    infoReturns = serialPort.ReadExisting();

                    foreach (string filename in System.IO.Directory.GetFiles(VR2C_COMMAND_FOLDER))
                    {
                        dynamic config = jsonParser.Parse(System.IO.File.ReadAllText(filename));
                        if (Regex.IsMatch(infoReturns, config.decoder.sentences["info_response"].format))
                        {
                            gotINFO = true;
                        }

                    }
                }
                read_attempts++;
            }
            if (read_attempts >= 5)
            {
                ReceiverExceptions re = new ReceiverExceptions(this, "(FATAL) Not able to get INFO from the VEMCO receiver attached on this port.", true);
                dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re, re.fatal,
                    this, this.portName, this.VEMCO_SerialNumber, null, null));
                serialPort.Close();
                throw re;
            }

            int RECEIVER_FW_VERSION = -1;
            if (infoReturns != "")
            {
                
                int fw_start = infoReturns.IndexOf("FW=");
                int fw_end = infoReturns.IndexOf(",", fw_start);
                string fw_ver = infoReturns.Substring((fw_start + 3), (fw_end - fw_start - 3));
                int fw_ver_firstperiod = fw_ver.IndexOf(".");
                int fw_ver_secondperiod = fw_ver.IndexOf(".", fw_ver_firstperiod + 1);
                string major = fw_ver.Substring(0, fw_ver_firstperiod);
                string minor = fw_ver.Substring(fw_ver_firstperiod + 1, (fw_ver_secondperiod - fw_ver_firstperiod - 1));
                string release = fw_ver.Substring(fw_ver_secondperiod + 1, (fw_ver.Length - fw_ver_secondperiod - 1));
                RECEIVER_FW_VERSION = (Int32.Parse(major) * 10000) + (Int32.Parse(minor) * 100) + (Int32.Parse(release));
            }
            dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("Detected firmware version: " + RECEIVER_FW_VERSION,
                this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, null));
            if (RECEIVER_FW_VERSION >= 0)
            {
                int fw_use = -1;

                foreach (string filename in System.IO.Directory.GetFiles(VR2C_COMMAND_FOLDER))
                {

                    string text = System.IO.File.ReadAllText(filename);
                    dynamic config = jsonParser.Parse(System.IO.File.ReadAllText(filename));

                    if (config.firmware_version >= fw_use && config.firmware_version <= RECEIVER_FW_VERSION)
                    {
                        fw_use = (Int32)config.firmware_version;
                        
                        encoder = new Encoder(commandPreamble, config);
                    }
                }
                if (fw_use < 0 || encoder == null)
                {
                    ReceiverExceptions re = new ReceiverExceptions(this, "(FATAL) Unable to parse out FW version from return from INFO command.", true);
                    dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re, re.fatal,
                        this, this.portName, this.VEMCO_SerialNumber, null, null));
                    serialPort.Close();
                    throw re;
                }
            }
            else
            {
                ReceiverExceptions re = new ReceiverExceptions(this, "(FATAL) Unable to parse out FW version from return from INFO command.", true);
                dispatcher.enqueueEvent(new RealTimeEvents.ExcepReceiver(re,re.fatal,
                    this, this.portName, this.VEMCO_SerialNumber, null, null));
                serialPort.Close();
                throw re;
            }
            Match matches = Regex.Match(infoReturns, encoder.encoderConfig.decoder.words["receiver_model"]);
            VEMCO_Model = matches.Groups[1].ToString();
            dispatcher.enqueueEvent(new RealTimeEvents.NoteReceiver("(receiver note) Successfully configured encoder with fw version = " + encoder.encoderConfig.firmware_version,
                this, this.portName, this.VEMCO_SerialNumber, this.VEMCO_Model, this.encoder.encoderConfig));
        }