351 lines
7.6 KiB
C#
351 lines
7.6 KiB
C#
/*
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Threading;
|
|
using System.IO.Ports;
|
|
using System.Xml;
|
|
|
|
namespace DMX2
|
|
{
|
|
public class DriverBoitierV1 : DriverDMX, IEventProvider
|
|
{
|
|
|
|
struct buttonState {
|
|
public buttonState(byte _button, bool _pressed){
|
|
button=_button; pressed=_pressed;
|
|
}
|
|
public byte button;
|
|
public bool pressed;
|
|
}
|
|
|
|
enum etatAutomate {
|
|
Deconnecte,
|
|
Transmission,
|
|
Erreur,
|
|
Reset,
|
|
Parametrage,
|
|
Fin
|
|
}
|
|
|
|
bool[] buttons = new bool[8];
|
|
bool[] watchButtons = new bool[8];
|
|
|
|
|
|
// tampons Entrée/Sortie
|
|
byte[] inputbuffer = new byte[1];
|
|
byte[] outputbuffer = new byte[260];
|
|
|
|
//Thread de boucle
|
|
Thread loopthread=null;
|
|
|
|
public UniversDMX patch=null;
|
|
|
|
string portname = "";
|
|
SerialPort serial = null;
|
|
|
|
public DriverBoitierV1 (string serialport, string id): base(id)
|
|
{
|
|
portname = serialport;
|
|
Start();
|
|
//serial = serialport;
|
|
outputbuffer[0]=27;
|
|
outputbuffer[1]=68;
|
|
outputbuffer[4]=255;
|
|
|
|
}
|
|
|
|
void Start ()
|
|
{
|
|
if (loopthread == null) {
|
|
loopthread = new Thread(new ThreadStart(MainLoop));
|
|
loopthread.Start();
|
|
}
|
|
}
|
|
|
|
void Connection ()
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine ("DriverV1.Connection()");
|
|
#endif
|
|
if (serial != null) {
|
|
serial.Close();
|
|
serial.Dispose();
|
|
serial = null;
|
|
}
|
|
if (!System.IO.File.Exists (portname)) {
|
|
Thread.Sleep (200);
|
|
return;
|
|
}
|
|
serial = new SerialPort(portname, 460800,Parity.None,8,StopBits.One);
|
|
serial.DtrEnable = false;
|
|
serial.ReadTimeout = 15;
|
|
serial.WriteTimeout = 200;
|
|
serial.Open();
|
|
etat = etatAutomate.Transmission;
|
|
}
|
|
|
|
volatile etatAutomate etat = etatAutomate.Deconnecte;
|
|
DateTime finAttente = DateTime.Now;
|
|
|
|
void MainLoop()
|
|
{
|
|
while(!disposed && etat != etatAutomate.Fin)
|
|
{
|
|
switch (etat) {
|
|
case etatAutomate.Deconnecte:
|
|
Connection();
|
|
Attente(DateTime.Now.AddMilliseconds(200));
|
|
break;
|
|
case etatAutomate.Transmission:
|
|
finAttente = DateTime.Now.AddMilliseconds (22);
|
|
EnvoiTrame();
|
|
Reception();
|
|
Attente(finAttente);
|
|
break;
|
|
case etatAutomate.Erreur:
|
|
Deconnecte();
|
|
Attente(DateTime.Now.AddSeconds(2));
|
|
break;
|
|
// case etatAutomate.Parametrage:
|
|
// EnvoiParam();
|
|
// break;
|
|
// case etatAutomate.Reset:
|
|
// EnvoiReset();
|
|
// break;
|
|
}
|
|
}
|
|
Deconnecte();
|
|
}
|
|
|
|
void Attente (DateTime date)
|
|
{
|
|
int sleeptime = (int) (date - DateTime.Now).TotalMilliseconds;
|
|
if(sleeptime>2)
|
|
Thread.Sleep(sleeptime);
|
|
|
|
while (DateTime.Now<date) Thread.Sleep(1);
|
|
}
|
|
|
|
void Deconnecte ()
|
|
{
|
|
etat = etatAutomate.Deconnecte;
|
|
if(serial == null) return;
|
|
|
|
serial.Close();
|
|
serial.Dispose();
|
|
}
|
|
|
|
void EnvoiTrame ()
|
|
{
|
|
try {
|
|
if(!serial.IsOpen) {
|
|
etat = etatAutomate.Erreur;
|
|
}
|
|
|
|
if(patch!=null) patch.CalculUnivers(outputbuffer,5,255);
|
|
|
|
serial.Write(outputbuffer,0,outputbuffer.Length);
|
|
|
|
} catch {
|
|
etat = etatAutomate.Erreur;
|
|
}
|
|
}
|
|
|
|
// void EnvoiParam ()
|
|
// {
|
|
// throw new NotImplementedException ();
|
|
// }
|
|
//
|
|
// void EnvoiReset ()
|
|
// {
|
|
// throw new NotImplementedException ();
|
|
// }
|
|
|
|
void Reception ()
|
|
{
|
|
try {
|
|
|
|
if(!serial.IsOpen || etat == etatAutomate.Erreur) {
|
|
etat = etatAutomate.Erreur;
|
|
return;
|
|
}
|
|
|
|
serial.Read(inputbuffer,0,inputbuffer.Length);
|
|
ProcessInput();
|
|
|
|
} catch {
|
|
etat = etatAutomate.Erreur;
|
|
}
|
|
}
|
|
|
|
|
|
void ProcessInput ()
|
|
{
|
|
byte b = 1; bool pressed;
|
|
for (byte i = 0; i<8; i++) {
|
|
if(!watchButtons[i]) continue;
|
|
pressed = !((inputbuffer[0] & b) != 0);
|
|
if(buttons[i]^pressed)
|
|
{
|
|
eventsPending.Enqueue(new buttonState(i,pressed));
|
|
buttons[i] = pressed;
|
|
}
|
|
b <<= 1;
|
|
}
|
|
}
|
|
|
|
public override void Dispose ()
|
|
{
|
|
disposed = true;
|
|
etat = etatAutomate.Fin;
|
|
if (loopthread != null) {
|
|
loopthread.Join ();
|
|
loopthread = null;
|
|
}
|
|
if(serial != null)
|
|
serial.Dispose();
|
|
|
|
}
|
|
#region implemented abstract members of DMX2.DriverDMX
|
|
public override Gtk.Widget GetUI ()
|
|
{
|
|
return new DriverBoitierV1UI(this);
|
|
}
|
|
#endregion
|
|
|
|
|
|
|
|
#region IEventProvider implementation
|
|
|
|
|
|
static System.Text.RegularExpressions.Regex regexEventID = new System.Text.RegularExpressions.Regex(
|
|
@"BV1-B(?<button>\d+)?",
|
|
System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
System.Collections.Concurrent.ConcurrentQueue<buttonState> eventsPending =
|
|
new System.Collections.Concurrent.ConcurrentQueue<buttonState>();
|
|
|
|
bool IEventProvider.Bind (string eventId)
|
|
{
|
|
var res = regexEventID.Match (eventId);
|
|
if (res.Success) {
|
|
int bt = int.Parse (res.Groups ["button"].Value);
|
|
if(bt<0||bt>7) return false;
|
|
watchButtons[bt] = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void IEventProvider.Unbind (string eventId)
|
|
{
|
|
var res = regexEventID.Match (eventId);
|
|
if (res.Success) {
|
|
int bt = int.Parse (res.Groups ["button"].Value);
|
|
if(bt<0||bt>7) return ;
|
|
watchButtons[bt] = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
Gtk.Menu IEventProvider.GetProviderSubMenu (EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler)
|
|
{
|
|
Gtk.Menu retmenu = new Gtk.Menu ();
|
|
|
|
Gtk.MenuItem evmenuitem = new Gtk.MenuItem ("Boutons");
|
|
retmenu.Add (evmenuitem);
|
|
Gtk.Menu evmenu = new Gtk.Menu ();
|
|
evmenuitem.Submenu = evmenu;
|
|
|
|
for (int i= 0; i<8;i++ ) {
|
|
Gtk.MenuItem item = new Gtk.MenuItem(string.Format("Bouton {0}",i+1));
|
|
item.Data[EventManager.EventIdKey] = string.Format("BV1-B{0}",i);
|
|
item.Data[EventManager.StateKey] = state;
|
|
item.ButtonPressEvent += handler;
|
|
evmenu.Add (item);
|
|
}
|
|
return retmenu;
|
|
}
|
|
|
|
void IEventProvider.ProcessEvents (EventManagerCallback callback)
|
|
{
|
|
buttonState bt;
|
|
EventData evd;
|
|
while (eventsPending.TryDequeue(out bt)) {
|
|
evd.id= string.Format("BV1-B{0}",bt.button );
|
|
evd.value = bt.pressed?(byte)0xFF:(byte)0x00;
|
|
evd.prev_value = (!bt.pressed)?(byte)0xFF:(byte)0x00;
|
|
callback(evd);
|
|
}
|
|
}
|
|
|
|
string IEventProvider.MenuName {
|
|
get {
|
|
return "Boitier V1";
|
|
}
|
|
}
|
|
|
|
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 ("DriverBoitierV1");
|
|
|
|
parent.AppendChild (el);
|
|
|
|
el.SetAttribute ("portname", portname.ToString ());
|
|
el.SetAttribute ("id", ID);
|
|
|
|
if(patch!=null) el.SetAttribute ("univers", patch.Nom);
|
|
}
|
|
#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");
|
|
|
|
DriverBoitierV1 drv = new DriverBoitierV1(port,id);
|
|
|
|
if(el.HasAttribute("univers"))
|
|
{
|
|
string univ = el.GetAttribute("univers");
|
|
foreach (UniversDMX u in conduite.Patches){
|
|
if(u.Nom== univ){
|
|
drv.patch = u;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return drv;
|
|
}
|
|
|
|
}
|
|
}
|
|
|