Zum Inhalt springen

Ein Event für FTDI - USB programmieren


Empfohlene Beiträge

Geschrieben

Hallo Forum,

ich bin das erste Mal in einem Forum. Bei mir geht es um folgendes:

ich habe ein Messsystem für Werkzeuge (CNC) mit folgenden Ausgängen entwickelt:

RS232, USB, LPT. Eine einfache Software in MS Visual C# 2008 soll die RS232 und USB verwalten. RS232 klappt, aber USB hat noch ein Problem. Ich verwende einen FTDI FT232R USB Controller. Als Virtueller COM-Port funktioniert die USB. Für Visual C# existiert die Datei FTD2XX_NET.dll. Nun möchte ich beim Empfang von Daten einen FT_EVENT_RXCHAR auslösen – und genau da haperts. Wie programmiere ich einen EVENT?

Über toolStripButton2_Click öffne ich die USB. Mit einer do – while Schleife konnte ich feststellen, das Daten ankommen. Bis auf ein EVENT fuktioniert alles.

Was habe ich bei der Aktivierung das EVENT falsch gemacht ????

Grüße JRinfo

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Windows;

using System.IO.Ports;

using System.IO;

using System.Runtime.InteropServices;

using FTD2XX_NET;

using System.Threading;


namespace WindowsFormsApplication1

{

    public partial class Form1 : Form

    {

        string daten;

        string readData;

        private string strPrintText;


        FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;

        FTDI myFtdiDevice = new FTDI();


        //einen EVENT erzeugen!!!!!!!!

        private EventWaitHandle DataReceived = new EventWaitHandle(false, EventResetMode.AutoReset);    // Handle for data received events

        BackgroundWorker DataHandler = new BackgroundWorker();  // Second thread for processing data received


        public Form1()

        {

            InitializeComponent();

            DataHandler.DoWork += new DoWorkEventHandler(DataHandler_DoWork);

        }


        private void Form1_Load(object sender, EventArgs e)

        {

            string[] ports = SerialPort.GetPortNames();

            foreach (string comname in ports)

            {

                toolStripDropDownButton1.DropDownItems.Add(comname);

            }

        }


        private void toolStripButton2_Click(object sender, EventArgs e) // USB öffnen

        {

            toolStripButton1.Checked = false;

            if (serialPort1.IsOpen)

                serialPort1.Close();

            if (toolStripButton2.Checked == true)

            {

                ftStatus = myFtdiDevice.OpenByDescription("WASI-MESSSYSTEM"); 

                if (ftStatus == FTDI.FT_STATUS.FT_OK)

                {

                    ftStatus = myFtdiDevice.SetBaudRate(115200);

                    if (ftStatus == FTDI.FT_STATUS.FT_OK)

                    {

                        ftStatus = myFtdiDevice.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_7, FTDI.FT_STOP_BITS.FT_STOP_BITS_2, FTDI.FT_PARITY.FT_PARITY_EVEN);

                        if (ftStatus == FTDI.FT_STATUS.FT_OK)

                        {

                            if (!DataHandler.IsBusy)

                                DataHandler.RunWorkerAsync();


                            //einen EVENT erzeugen!!!!!!!!

                            ftStatus = myFtdiDevice.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, DataReceived);

                            if (ftStatus != FTDI.FT_STATUS.FT_OK)

                            {

                            }

                        }

                    }

                }

            }

            else

            {

                if (myFtdiDevice.IsOpen == true)

                {

                    myFtdiDevice.Close();

                }

            }

        }


        void DataHandler_DoWork(object sender, DoWorkEventArgs e)

        {

            uint numBytes = 0;


            if ((ftStatus = myFtdiDevice.GetRxBytesAvailable(ref numBytes)) == FTDI.FT_STATUS.FT_OK)

            {

                if ((ftStatus = myFtdiDevice.Read(out readData, numBytes, ref numBytes)) == FTDI.FT_STATUS.FT_OK)

                {

                    daten = daten + readData;

                }

            }

        }


        private void toolStripDropDownButton1_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)

        {

            toolStripButton1.Text = e.ClickedItem.Text;

        }


        private void toolStripButton1_Click(object sender, EventArgs e)

        {

            toolStripButton2.Checked = false;

            if (toolStripButton1.Checked == true)

            {

                if (myFtdiDevice.IsOpen == true)

                {

                    myFtdiDevice.Close();

                }

                if (!serialPort1.IsOpen)

                {

                    try

                    {

                        serialPort1.BaudRate = 9600;

                        serialPort1.DataBits = 7;

                        serialPort1.StopBits = StopBits.Two;

                        serialPort1.Parity = Parity.Even;

                        serialPort1.Handshake = Handshake.None;

                        serialPort1.Open();

                    }

                    catch

                    {

                        string message = serialPort1.PortName + " kann nich geöffnet werden!\nWird vermutlich von einer anderen Anwendung benutzt";

                        MessageBoxIcon icon = MessageBoxIcon.Information;

                        MessageBoxButtons button = MessageBoxButtons.OK;

                        MessageBox.Show(message, "Information", button, icon);

                        toolStripButton1.Checked = false;

                    }

                }


            }

            else

            {

                if (serialPort1.IsOpen)

                    serialPort1.Close();

            }

        }


        private void toolStripButton5_Click(object sender, EventArgs e)

        {

            this.richTextBox1.Clear();

            daten = "";

        }


        private void DisplayText(object sender, EventArgs e)

        {

            richTextBox1.AppendText(daten);

        }


        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)

        {

            int C = serialPort1.BytesToRead;

            int X;

            char chr;

            for (X = 0; X < C; X++)

            {

                chr = Convert.ToChar(serialPort1.ReadByte());

                if (chr == '%')

                {

                    this.Invoke(new EventHandler(DisplayText));

                }

                else

                    daten = daten + chr;

            }

        }


        private void toolStripButton7_Click(object sender, EventArgs e)

        {

            printDialog1.Document = printDocument1;

            if (printDialog1.ShowDialog() == DialogResult.OK)

            {

                strPrintText = richTextBox1.Text;

                printDocument1.Print();

            }

        }


        private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)

        {

            StringFormat stringFormat = new StringFormat();

            Pen blackPen = new Pen(Color.Black, 3);

            RectangleF rectFPapier, rectFText;

            rectFPapier = e.MarginBounds;

            rectFText = RectangleF.Inflate(rectFPapier, 0, -2 * richTextBox1.Font.GetHeight(e.Graphics));

            stringFormat.Trimming = StringTrimming.Word;

            e.Graphics.DrawString(strPrintText, richTextBox1.Font, Brushes.Black, rectFText, stringFormat);

        }


    }

}

  • 2 Wochen später...
Geschrieben

hi,

So wie ich das sehe, ist das kein 'regulärer' .NET event sondern eher ein 'Thread event' (keine Ahnung wie das richtig heist...).

Ich habe das folgendermaßen gelöst:


private AutoResetEvent recvDataEvent;

private BackgroundWorker worker;


void open() {

	COM.OpenByIndex(smartBoxIndex);

	COM.SetBaudRate(115200);

	COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8,FTDI.FT_STOP_BITS.FT_STOP_BITS_1,FTDI.FT_PARITY.FT_PARITY_NONE);

	COM.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_NONE,0,0);


	recvDataEvent = new AutoResetEvent(false);

	COM.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR,recvDataEvent);


	worker = new BackgroundWorker();

	worker.DoWork += new DoWorkEventHandler(worker_DoWork);

	worker.RunWorkerAsync();

}


void worker_DoWork(object sender, DoWorkEventArgs e)

{

	uint bytesToRead = 0;

	uint bytesRead = 0;


	while (true) {

		// wait until event is fired

		this.recvDataEvent.WaitOne(); 


		// try to recieve data now

		if(FTDI.FT_STATUS.FT_OK == this.COM.GetRxBytesAvailable(ref bytesToRead)) {

			byte[] buffer = new byte[bytesToRead];

			if(FTDI.FT_STATUS.FT_OK == this.COM.Read(buffer,bytesToRead,ref bytesRead)) {

				if (bytesToRead != bytesRead) {

					Log("Data length error!");

				}

				foreach (byte b in buffer) {

					recvBuffer.Enqueue(;

				}

				Log(ByteArrayToHexString(buffer));

			}

		}

	}

}




[/code]

evtl nicht der eleganteste Weg, aber immerhin klappt es ;)

Eine Frage am Rande:

Dein Projekt scheint so ähnlich zu sein wie das, was ich im Moment bearbeite. Nur habe ich ein Problem:

Gibt es eine Möglichkeit die Zeit zu bestimmen an der die Daten im Puffer ankommen (Abweichung max. 0,5 ms) ? (bezogen auf die SerialPort klasse meine ich jetzt, da ich auch beides implementiere)

Geschrieben (bearbeitet)

Mal ne Frage, die FTDI-Klasse die da verwendet wird ist das zufällig die welche es unter

C# Examples

direkt oben als managed .NET wrapper gibt?

Falls ja, wie geht ihr mit den Mesageboxen um? Keine Ahnung was sich FTDI dabei gedacht hat, aber wenn man sich die einzelnen Funktionen mal im Reflector anschaut, sehen die immer so inetwa aus

public FT_STATUS functionname(params)

{

  tests ob ausführung ok ist

  functionscode

        if (mögliche fehlerquelle 1)

        {

            MessageBox.Show("fehlertext1");

        }

        if (mögliche fehlerquelle 2)

        {

            MessageBox.Show("fehlertext 2");

        }

  ...

    }

    return ft_status;

}



und mal ehrlich ich will doch nicht das eine DLL dem User Messageboxen entgegenschmeißt, anstatt mir eine Exception hochzugeben, über deren Behandlung ich mir dann selbst Gedanken machen kann und falls nötig eine messagebox erzeuge.

Zum erzeugen von Events

in meinem aktuellen Projekt auf Arbeit arbeite ich auf mit nem FTDI-Chip über den Chip läuft ein selbst definiertes Protokoll das auf C# Seite über einen Backgroundworker abgearbeitet wird.

Dabei wird nur ein Stream ansich benötigt und dann Streamspezifische funktionen verwendet.

So kann man USB und Serial auf einmal erschlagen.

Eine FTDI-Streamklasse implementiert read/write.

Anschließend liest der Protokollhandler ankommende Daten in einen Puffer und sobald ein gültiges Paket erkannt wurde schmeißt er ein Event.

Bearbeitet von kross
Geschrieben
So kann man USB und Serial auf einmal erschlagen.

Benutzt du auch die Serial Port Klasse? Kannst evtl. mal ein kleines Schnipsel posten?

Zu deinem Problem:

Also ich denke da hast du was falsch verstanden, die DLL bietet lediglich keine Exceptions, aber wirft dir natürlich auch keine Messageboxen ins Gesicht ;)

Die Fehlerbehandlung erfolgt über so ne Art Statusenum:



ftStatus = Mach_Irgendwas(bla);

if ( ftStatus != FTDI.FT_STATUS.FT_OK ) {

;

} else {

Debug.Log("alles klar");

}


mfg

Geschrieben

Du verstehst da etwas falsch.

ftStatus = Mach_Irgendwas(bla);

In dem Fall führt ja Mach_Irgendwas code innerhalb der FTDI-Klasse aus, die du als DLL hast, und genau darin sind MessageBoxen für bestimmte Fehler fest im Code...

zum code erstelle einfach 2 Klassen FTDI und ComportStream die du von System.IO.Stream ableitest VS bietet dir dann von allein an die abstrakten Funktionen zu implementieren.

dann


      SerialPort m_comport = null;


        public ComPortStream(SerialPort _comport)

        {

            m_comport = _comport;           

        }


		 public override int Read(byte[] buffer, int offset, int count)

        {

            return m_comport.Read(buffer, offset, count);

        }


		 public override void Write(byte[] buffer, int offset, int count)

        {

            m_comport.Write(buffer, offset, count);

        }


        private static Dictionary<FTDI, FTDIStream> m_instances;


        public static FTDIStream getInstance(FTDI _ftdi)

        {

            if (m_instances == null)

                m_instances = new Dictionary<FTDI, FTDIStream>();

            if(m_instances.ContainsKey(_ftdi))

            {

                return m_instances[_ftdi];

            }

            else

            {

                FTDIStream stream = new FTDIStream(_ftdi);

                m_instances.Add(_ftdi, stream);

                return m_instances[_ftdi];

            }

        }


        public static void removeInstance(FTDI _ftdi)

        {

            if(m_instances.ContainsKey(_ftdi))

            {

                m_instances.Remove(_ftdi);

            }

        }


        private FTDI m_ftdi;


        public FTDIStream(FTDI _ftdi)

        {

            if (_ftdi == null)

                throw new NullReferenceException();

            m_ftdi = _ftdi;

        }


        public override void Flush()

        {

            m_ftdi.Purge(FTD2XX_NET.FTDI.FT_PURGE.FT_PURGE_RX);

            m_ftdi.Purge(FTD2XX_NET.FTDI.FT_PURGE.FT_PURGE_TX);

        }


		        public override int Read(byte[] buffer, int offset, int count)

        {

            if (buffer == null)

                throw new NullReferenceException();

            if (buffer.Length < count)

                throw new Exception("Buffer to small.");


            byte[] tempbuffer = new byte[offset + count];

            uint bytesread = 0;

            m_ftdi.Read(tempbuffer, (uint)tempbuffer.Length, ref bytesread);

            Buffer.BlockCopy(tempbuffer, offset, buffer, 0, (int)((count + offset >= bytesread) ? ((bytesread - offset > 0) ? bytesread - offset : 0) : count));


            return (int)((count + offset >= bytesread) ? ((bytesread - offset > 0) ? bytesread - offset : 0) : count);

        }


        public override void Write(byte[] buffer, int offset, int count)

        {

            if (buffer == null)

                throw new NullReferenceException();

            if (offset > buffer.Length)

                throw new Exception("Offset greater then Buffersize");

            byte[] writebuffer = new byte[buffer.Length - offset];

            Buffer.BlockCopy(buffer, offset, writebuffer, 0, writebuffer.Length);

            uint byteswritten = 0;

            FTDI.FT_STATUS status = m_ftdi.Write(writebuffer, count, ref byteswritten);

        }


		        public override long Length

        {

            get

            {

                uint retval = 0;

                m_ftdi.GetRxBytesAvailable(ref retval);

                return retval;

            }

        }




der fdtistram ist schon deutlich mehr getestet als die comportvariante die hab ich nur mal halbherzig implementiert

Geschrieben
ftStatus = Mach_Irgendwas(bla);

In dem Fall führt ja Mach_Irgendwas code innerhalb der FTDI-Klasse aus

Hm... also ich hab jedenfalls noch keine Messagebox gesehn. Egal welche Funktion ausgeführt wurde.

Und wie machst du das mit den Timings?

Ich krieg keine Zeitmessung < 10 ms hin. Ist das überhaupt möglich? Ich weiss ja nämlich garnicht wann die Daten in den Buffer geschrieben werden :?

Geschrieben

Für mich ist nur wichtig das die Daten überhaupt kommen.

Über den USB-Port werden Kundenspezifische Konfigurationsdaten geschrieben oder das Eventlog ausgelesen oder die Firmware upgedated aber nichts timingspezifisches wie ankommende Messwerte ohne eigenes Timestamp.

Wenn ich Zeitangaben bräuchte hätte ich das Glück die Firmware gleich mitzuprogrammieren.

Wenn das nicht der Fall wäre würde ich dann aber nix anderes als Möglichkeit sehen als in einem Backgroundworker den Puffer permanent schnell auszulesen mir das aktuelle Datetime des ankommens der Daten zu merken mit den Daten zusammen in die Eventargs des Receiveevents packen und dann oberhalb zu schauen ob ich mit den Timespans zwischen meinen Eventargs auf sinnvolle Werte komme.

Geschrieben

DateTime ist leider zu ungenau,... habs jetzt mit eine Tickcount für jedes empfangene byte versucht.

Hat aber immernoch das gleiche problem, allerdings wesentlich seltener.

Messgenauigkeit liegt nun etwa im 3-5 ms bereich.

mfg

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...