/* Copyright (C) Arnaud Houdelette 2012-2014 Copyright (C) Emmanuel Langlois 2012-2014 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Threading; using System.IO.Ports; using System.Xml; using System.Collections.Generic; namespace DMX2 { public class DriverBoitierV3 : DriverDMX, IEventProvider { struct dmxState { public dmxState(int _dmx, byte _value){ value=_value; dmx=_dmx; } public int dmx; public byte value; } enum etatAutomate { Deconnecte, Transmission, Erreur, Fin } const int timeout = 500; // tampons Entrée/Sortie public byte[] inputbuffer = new byte[517]; byte[] outputbuffer = new byte[514]; //Thread de boucle Thread loopthread=null; public UniversDMX patch1=null; string portname = ""; SerialPort serial = null; int brk = 150; int mab = 50; int nbc1 = 512; byte flags = 0; byte dmxinterval= 40; int usbrefresh = 40; bool sync=false; bool reinit=false ; public void ReInit () { reinit=true; } public int Break { set { brk = value; paramFlag = true; } get { return brk; } } public int Mab { set { mab = value; paramFlag = true; } get { return mab; } } public bool Merge { set { flags = (byte)( (flags & 0xFE) | (value?1:0)); paramFlag = true; } get { return (flags&1)>0; } } public bool Sync { get { return sync; } set { flags = (byte)( (flags & 0xFD) | (value?2:0)); sync = value; } } public int NbCircuits { get { return nbc1; } set { nbc1 = value; paramFlag= true; } } public byte DmxInterval { get { return dmxinterval; } set { dmxinterval = value; paramFlag= true; } } public int UsbRefresh { get { return usbrefresh; } set { usbrefresh = value; } } public DriverBoitierV3 (string serialport, string id): base(id) { patch1 = Conduite.Courante.Patches[0]; portname = serialport; outputbuffer[0]=27; outputbuffer[1]=68; Start(); } bool paramFlag = false; void Start () { if (loopthread == null) { loopthread = new Thread(new ThreadStart(MainLoop)); loopthread.Start(); } } void Connection () { Console.WriteLine ("DriverV3.Connection()"); if (serial != null) { serial.Close (); serial.Dispose (); serial = null; } if (!System.IO.File.Exists (portname)) { Thread.Sleep (1500); return; } serial = new SerialPort (portname); Console.WriteLine (portname); try { serial.RtsEnable = true; serial.Open (); if(Synchronisation()) etat = etatAutomate.Transmission; else { serial.Close(); etat = etatAutomate.Deconnecte; } } catch (Exception ex) { etat = etatAutomate.Deconnecte; Console.WriteLine("DriverV3:Connection : {0}",ex); Thread.Sleep (1500); } } /// /// Synchronise le pilote et le boitier ... /// Après connexion ou erreur /// bool Synchronisation () { //return true; Console.WriteLine ("DriverV3.Synchronisation()"); if (serial == null) return false; if (!serial.IsOpen) return false; byte[] tmpBuffer = new byte[2]; // On attends un peu Thread.Sleep (5); // Vide le buffer d'entree if (serial.BytesToRead > 0) serial.ReadExisting (); // on envoie Esc 'A' tmpBuffer [0] = 27; tmpBuffer [1] = 65; serial.Write (tmpBuffer, 0, 2); // On attends un peu if(!WaitForData (1)) { return false; } paramFlag = true; serial.Read(tmpBuffer,0,1); if(tmpBuffer[0] == 65) return true; return false; } void DmxSync () { if (!serial.IsOpen) { etat = etatAutomate.Erreur; return; } byte[] tmpBuffer = new byte[2]; tmpBuffer [0] = 27; // Esc tmpBuffer [1] = 65; // 'A' serial.Write (tmpBuffer, 0, tmpBuffer.Length); if(!WaitForData (1)) { etat = etatAutomate.Erreur; return ; } serial.Read(tmpBuffer,0,1); if(tmpBuffer[0] != 65) etat = etatAutomate.Erreur; } volatile etatAutomate etat = etatAutomate.Deconnecte; DateTime finAttente = DateTime.Now; int compteErreur = 0; void MainLoop () { //DateTime t = DateTime.Now; while (!disposed && etat != etatAutomate.Fin) { try { switch (etat) { case etatAutomate.Deconnecte: Connection (); compteErreur = 0; break; case etatAutomate.Transmission: finAttente = DateTime.Now.AddMilliseconds (usbrefresh); //Console.WriteLine(DateTime.Now-t); //t = DateTime.Now; if(sync)DmxSync(); EnvoiTrame (); Reception (); Attente (finAttente); if (paramFlag) Parametrage (); if (reinit) EnvoieReInit(); break; case etatAutomate.Erreur: Console.WriteLine("DriverV3 : etatAutomate.Erreur"); compteErreur ++; Deconnecte (); Attente (DateTime.Now.AddSeconds (2)); break; // case etatAutomate.Parametrage: // EnvoiParam(); // break; // case etatAutomate.Reset: // EnvoiReset(); // break; } } catch (Exception ex) { Console.WriteLine("Exception dans DriverV3 : {0}",ex); if(etat != etatAutomate.Fin) etat = etatAutomate.Erreur; } } Deconnecte(); } void Attente (DateTime date) { int sleeptime = (int) (date - DateTime.Now).TotalMilliseconds-1; if(sleeptime>2) Thread.Sleep(sleeptime); while (DateTime.Now 0) Thread.Sleep(1); serial.Write(outputbuffer,0,outputbuffer.Length); } catch (Exception ex) { Console.WriteLine("Exception Envoi {0}",ex); etat = etatAutomate.Erreur; } } bool WaitForData (int len) { int wcnt =0 ; while (serial.BytesToRead < len) { Thread.Sleep (1); if (++wcnt > timeout) return false; } return true; } // void EnvoiParam () // { // throw new NotImplementedException (); // } // // void EnvoiReset () // { // throw new NotImplementedException (); // } byte flag_input; void Reception () { try { if(!serial.IsOpen || etat == etatAutomate.Erreur) { etat = etatAutomate.Erreur; return; } if(!WaitForData (inputbuffer.Length)) { etat = etatAutomate.Erreur; Console.WriteLine("DriverV3.Reception : attente depassee"); return ; } serial.Read(inputbuffer,0,inputbuffer.Length); if (flag_input != inputbuffer[512]) { flag_input = inputbuffer[512]; Console.WriteLine(flag_input ); } if(serial.BytesToRead>0) serial.ReadExisting (); ProcessData(); //Console.WriteLine("DriverV3.Reception : OK"); compteErreur= 0; } catch (Exception ex) { Console.WriteLine(serial.BytesToRead); Console.WriteLine("Exception Reception {0}",ex); etat = etatAutomate.Erreur; } } void Parametrage () { Console.WriteLine ("DriverV3.Parametrage()"); paramFlag = false; if (!serial.IsOpen) { etat = etatAutomate.Erreur; return; } byte[] tmpBuffer = new byte[7]; tmpBuffer [0] = 27; // Esc tmpBuffer [1] = 66; // 'B' tmpBuffer [2] = // nb circuits (byte)(nbc1 / 2 - 1); tmpBuffer [3] = (byte)brk; tmpBuffer [4] = (byte)mab; tmpBuffer [5] = (byte) (flags ); tmpBuffer [6] = (byte) (dmxinterval); serial.Write (tmpBuffer, 0, tmpBuffer.Length); if(!WaitForData (1)) { etat = etatAutomate.Erreur; return ; } serial.Read(tmpBuffer,0,1); if(tmpBuffer[0] != 66) etat = etatAutomate.Erreur; } void EnvoieReInit() { reinit = false; if (!serial.IsOpen) { etat = etatAutomate.Erreur; return; } byte[] tmpBuffer = new byte[2]; tmpBuffer [0] = 27; // Esc tmpBuffer [1] = 67; // 'B' serial.Write (tmpBuffer, 0, tmpBuffer.Length); if(!WaitForData (1)) { etat = etatAutomate.Erreur; return ; } serial.Read(tmpBuffer,0,1); if(tmpBuffer[0] != 67) etat = etatAutomate.Erreur; } void ProcessData () { lock(watchdmx) foreach (int dmx in watchdmx) { if( inputbuffer[dmx]!= lastVal[dmx]){ lastVal[dmx] = inputbuffer[dmx]; eventsPending.Enqueue(new dmxState(dmx,inputbuffer[dmx])); } } } public override void Dispose () { disposed = true; etat = etatAutomate.Fin; if (loopthread != null) { loopthread.Join (); loopthread = null; } //TODO : Close Port if(serial != null) serial.Dispose(); } #region implemented abstract members of DMX2.DriverDMX public override Gtk.Widget GetUI () { return new DriverBoitierV3UI(this); } #endregion #region IEventProvider implementation List watchdmx = new List(); Dictionary lastVal = new Dictionary(); static System.Text.RegularExpressions.Regex regexEventID = new System.Text.RegularExpressions.Regex( @"BV3-D(?\d+)?", System.Text.RegularExpressions.RegexOptions.Compiled); System.Collections.Concurrent.ConcurrentQueue eventsPending = new System.Collections.Concurrent.ConcurrentQueue(); bool IEventProvider.Bind (string eventId) { var res = regexEventID.Match (eventId); if (res.Success) { int dmx = int.Parse (res.Groups ["dmx"].Value); if(dmx<0||dmx>511) return false; lock(watchdmx){ if(!watchdmx.Contains(dmx)) { watchdmx.Add(dmx); lastVal[dmx] = 0; } } return true; } return false; } void IEventProvider.Unbind (string eventId) { var res = regexEventID.Match (eventId); if (res.Success) { int dmx = int.Parse (res.Groups ["dmx"].Value); if(dmx<1||dmx>512) return; lock(watchdmx) watchdmx.Remove (dmx); return; } return; } Gtk.Menu IEventProvider.GetProviderSubMenu (EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler) { Gtk.Menu retmenu = new Gtk.Menu (); Gtk.MenuItem evmenuitem = new Gtk.MenuItem ("Entrée DMX"); retmenu.Add (evmenuitem); Gtk.Menu evmenu = new Gtk.Menu (); evmenuitem.Submenu = evmenu; for (int c = 0; c<512; c+=100) { Gtk.MenuItem citem = new Gtk.MenuItem(string.Format("De {0} à {1}", c==0?1:c, c==500?512:c+99 )); Gtk.Menu cmenu = new Gtk.Menu(); citem.Submenu = cmenu; evmenu.Add(citem); for(int d=0 ; d<100;d+=10){ if(c+d>512) break; Gtk.MenuItem ditem = new Gtk.MenuItem(string.Format("De {0} à {1}", c+d==0?1:c+d, c+d==510?512:c+d+9 )); Gtk.Menu dmenu = new Gtk.Menu(); ditem.Submenu = dmenu; cmenu.Add(ditem); for(int u=0; u<10;u++){ if(c+d+u==0) continue; if(c+d+u>512) break; Gtk.MenuItem uitem = new Gtk.MenuItem(string.Format("Entrée DMX {0}",c+d+u)); uitem.Data[EventManager.EventIdKey] = string.Format("BV3-D{0}",c+d+u); uitem.Data[EventManager.StateKey] = state; uitem.ButtonPressEvent += handler; dmenu.Add (uitem); } } } return retmenu; } void IEventProvider.ProcessEvents (EventManagerCallback callback) { dmxState dmxs; EventData evd; while (eventsPending.TryDequeue(out dmxs)) { evd.id= string.Format("BV3-D{0}",dmxs.dmx ); evd.value = dmxs.value; callback(evd); } } string IEventProvider.MenuName { get { return "Boitier V3"; } } IFeedbackInfo IEventProvider.GetFeedbackInfo (string eventId) { return null; } #endregion #region implemented abstract members of DMX2.DriverDMX public override void Save (System.Xml.XmlElement parent) { System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("DriverBoitierV3"); parent.AppendChild (el); el.SetAttribute ("portname", portname.ToString ()); el.SetAttribute ("id", ID); if(patch1!=null) el.SetAttribute ("univers1", patch1.Nom); el.SetAttribute("circuits", nbc1.ToString()); el.SetAttribute("mab",mab.ToString()); el.SetAttribute("brk",brk.ToString()); el.SetAttribute("merge1",((flags&1)>0).ToString()); el.SetAttribute("sync",sync.ToString()); el.SetAttribute("dmxinterval",dmxinterval.ToString()); el.SetAttribute("usbrefresh",usbrefresh.ToString()); } #endregion public static new DriverDMX Load(Conduite conduite, XmlElement el) { //System.Xml.XmlElement xmlE; string port = el.GetAttribute("portname"); if(! System.IO.File.Exists(port)) return null; string id = el.GetAttribute("id"); DriverBoitierV3 drv = new DriverBoitierV3(port,id); if(el.HasAttribute("univers1")) { string univ = el.GetAttribute("univers1"); foreach (UniversDMX u in conduite.Patches){ if(u.Nom== univ){ drv.patch1 = u; break; } } } drv.NbCircuits = int.Parse(el.TryGetAttribute("circuits","512")); drv.Mab = int.Parse(el.TryGetAttribute("mab","150")); drv.Break = int.Parse(el.TryGetAttribute("brk","50")); drv.Merge = bool.Parse(el.TryGetAttribute("merge1","True")); drv.Sync = bool.Parse(el.TryGetAttribute("sync","True")); drv.DmxInterval = byte.Parse(el.TryGetAttribute("dmxinterval","22")); drv.UsbRefresh = int.Parse(el.TryGetAttribute("usbrefresh","22")); return drv; } } }