/ src / libserver / eibusb.cpp
eibusb.cpp
  1  /*
  2      EIBD eib bus access and management daemon
  3      Copyright (C) 2005-2011 Martin Koegler <mkoegler@auto.tuwien.ac.at>
  4  
  5      This program is free software; you can redistribute it and/or modify
  6      it under the terms of the GNU General Public License as published by
  7      the Free Software Foundation; either version 2 of the License, or
  8      (at your option) any later version.
  9  
 10      This program is distributed in the hope that it will be useful,
 11      but WITHOUT ANY WARRANTY; without even the implied warranty of
 12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13      GNU General Public License for more details.
 14  
 15      You should have received a copy of the GNU General Public License
 16      along with this program; if not, write to the Free Software
 17      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 18  */
 19  
 20  #include "eibusb.h"
 21  
 22  #include "cemi.h"
 23  #include "emi1.h"
 24  #include "emi2.h"
 25  #include "usblowlevel.h"
 26  
 27  /* add formatter for fmt >= 10.0.0 */
 28  int format_as(EMIVer t) { return t; }
 29  
 30  USBConverterInterface::USBConverterInterface (LowLevelIface * p, IniSectionPtr& s)
 31    : LowLevelFilter(p,s)
 32  {
 33    t->setAuxName("Conv");
 34    sendLocal_done.set<USBConverterInterface,&USBConverterInterface::sendLocal_done_cb>(this);
 35    iface = new USBLowLevelDriver(this, s);
 36  }
 37  
 38  USBConverterInterface::~USBConverterInterface ()
 39  {
 40  }
 41  
 42  void
 43  USBConverterInterface::send_Data (CArray& l)
 44  {
 45    if (version == vRaw)
 46      {
 47        iface->send_Data (l);
 48        return;
 49      }
 50    if (version < vEMI1 || version > vCEMI)
 51      {
 52        ERRORPRINTF (t, E_ERROR | 48, "EMI version %s during send",version);
 53        return;
 54      }
 55    t->TracePacket (0, "Send-EMI", l);
 56    CArray out;
 57    unsigned int j, l1;
 58    l1 = l.size();
 59    out.resize (64);
 60    if (l1 + 11 > 64)
 61      l1 = 64 - 11;
 62    for (j = 0; j < out.size(); j++)
 63      out[j] = 0;
 64    for (j = 0; j < l1; j++)
 65      out[j + 11] = l[j];
 66    out[0] = 1;
 67    out[1] = 0x13;
 68    out[2] = l1 + 8;
 69    out[3] = 0x0;
 70    out[4] = 0x08;
 71    out[5] = 0x00;
 72    out[6] = l1;
 73    out[7] = 0x01;
 74    out[8] = version;
 75    iface->send_Data (out);
 76  }
 77  
 78  void
 79  USBConverterInterface::recv_Data(CArray& res)
 80  {
 81    if (version == vRaw)
 82      {
 83        //t->TracePacket (0, "RecvEMI raw", res);
 84        LowLevelFilter::recv_Data(res);
 85        return;
 86      }
 87  
 88    if (res.size() != 64)
 89      goto out;
 90    if (res[0] != 0x01)
 91      goto out;
 92    if ((res[1] & 0x0f) != 3) // single-frame packet // TODO
 93      goto out;
 94    if (res[2] > 64 - 8) // full packet length
 95      goto out;
 96    if (res[3] != 0)
 97      goto out;
 98    if (res[4] != 8)
 99      goto out;
100    if (res[5] != 0)
101      goto out;
102    if (res[6] + 11 > 64) // len
103      goto out;
104    if (res[7] != 1)
105      goto out;
106    switch (version)
107      {
108      case vEMI1:
109        if (res[8] != 1)
110          goto out;
111        break;
112      case vEMI2:
113        if (res[8] != 2)
114          goto out;
115        break;
116      case vCEMI:
117        if (res[8] != 3)
118          goto out;
119        break;
120      default:
121        goto out;
122      }
123  
124    {
125      CArray res1(res.data() + 11, res[6]);
126      t->TracePacket (0, "RecvEMI", res1);
127      LowLevelFilter::recv_Data(res1);
128      return;
129    }
130  
131  out:
132    t->TracePacket (8, "RecvEMI:deleted", res);
133    return;
134  }
135  
136  USBDriver::USBDriver (const LinkConnectPtr_& c, IniSectionPtr& s) : LowLevelAdapter (c,s)
137  {
138    t->setAuxName("USBdr");
139    sendLocal_done.set<USBDriver,&USBDriver::sendLocal_done_cb>(this);
140  }
141  
142  void
143  USBConverterInterface::send_Init()
144  {
145    TRACEPRINTF (t, 2, "send_Init %d",version);
146  
147    uint8_t init[64] =
148    {
149      0x01, 0x13, 0x0a, 0x00, 0x08, 0x00, 0x02, 0x0f, 0x03, 0x00, 0x00, 0x05, 0x01
150    };
151    init[12] = version;
152    send_Local (CArray (init, sizeof (init)), 1);
153  }
154  
155  void
156  USBConverterInterface::sendLocal_done_cb(bool success)
157  {
158    if (!success)
159      stop(true);
160    else
161      LowLevelFilter::started();
162  }
163  
164  void
165  USBDriver::started()
166  {
167    if (version == vUnknown)
168      {
169        version = vDiscovery;
170        timeout.set<USBDriver,&USBDriver::timeout_cb>(this);
171        is_local = false; // was set by xmit => send_Local
172        xmit();
173        return;
174      }
175  
176    LowLevelAdapter::started();
177  }
178  
179  void
180  USBDriver::timeout_cb(ev::timer &, int)
181  {
182    if (++cnt < 5)
183      xmit();
184    else
185      {
186        ERRORPRINTF (t, E_ERROR | 49, "No reply to setup");
187        version = vTIMEOUT;
188        stop(true);
189      }
190  }
191  
192  void
193  USBDriver::stopped(bool err)
194  {
195    if (version == vDiscovery)
196      timeout.stop();
197    LowLevelAdapter::stopped(err);
198  }
199  
200  void
201  USBDriver::do_send_Next()
202  {
203    if (version >= vEMI1 && version <= vCEMI)
204      HWBusDriver::send_Next();
205  }
206  
207  void
208  USBDriver::xmit()
209  {
210    const uint8_t ask[64] =
211    {
212      0x01, 0x13, 0x09, 0x00, 0x08, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x00, 0x01
213    };
214    timeout.start(1,0);
215    send_Local (CArray (ask, sizeof (ask)), 1);
216  }
217  
218  void
219  USBDriver::sendLocal_done_cb(bool success)
220  {
221    if (!success)
222      {
223        timeout.stop();
224        stop(true);
225      }
226    else if (wait_make)
227      {
228        wait_make = false;
229        if(!make_EMI())
230          stop(true);
231      }
232    else if (version > vERROR && version < vRaw)
233      iface->started();
234  }
235  
236  void
237  USBDriver::recv_Data(CArray& c)
238  {
239    t->TracePacket (2, "recv_Data", c);
240    if (version > vERROR && version <= vRaw)
241      {
242        LowLevelAdapter::recv_Data(c);
243        return;
244      }
245    if (version != vDiscovery)
246      {
247        TRACEPRINTF (t, 2, "Data during version=%d", version);
248        return;
249      }
250    if (c.size() != 64)
251      goto cont;
252    if (c[0] != 01)
253      goto cont;
254    if ((c[1] & 0x0f) != 0x03)
255      goto cont;
256    if (c[2] != 0x0b)
257      goto cont;
258    if (c[3] != 0x00)
259      goto cont;
260    if (c[4] != 0x08)
261      goto cont;
262    if (c[5] != 0x00)
263      goto cont;
264    if (c[6] != 0x03)
265      goto cont;
266    if (c[7] != 0x0F)
267      goto cont;
268    if (c[8] != 0x02)
269      goto cont;
270    if (c[11] != 0x01)
271      goto cont;
272    if (c[13] & 0x2)
273      version = vEMI2;
274    else if (c[13] & 0x1)
275      version = vEMI1;
276    else if (c[13] & 0x4)
277      version = vCEMI;
278    else
279      {
280        TRACEPRINTF (t, 2, "version x%02x not recognized", c[13]);
281        version = vERROR;
282        timeout.stop();
283        stop(true);
284        return;
285      }
286  
287    timeout.stop();
288    TRACEPRINTF (t, 1, "Using EMI version %d", version);
289  
290    if (is_local) // the inquiry's send_local has not yet been acked
291      {
292        TRACEPRINTF (t, 0, "version x%02x recognized, delayed", c[13]);
293        wait_make = true;
294        return;
295      }
296  
297    if(!make_EMI())
298      {
299        stop(true);
300        return;
301      }
302  
303    return;
304  
305  cont:
306    TRACEPRINTF (t, 2, "not recognized");
307    return;
308  }
309  
310  bool
311  USBDriver::make_EMI()
312  {
313    if (version != vUnknown)
314      {
315        usb_iface->version = version;
316        usb_iface->send_Init();
317      }
318    switch (version)
319      {
320      case vEMI1:
321        iface = new EMI1Driver (this,cfg, iface);
322        break;
323      case vEMI2:
324        iface = new EMI2Driver (this,cfg, iface);
325        break;
326      case vCEMI:
327        iface = new CEMIDriver (this,cfg, iface);
328        break;
329      case vRaw:
330        return true;
331      case vUnknown:
332        iface = nullptr;
333        return true;
334      default:
335        TRACEPRINTF (t, 2, "Unsupported EMI");
336        return false;
337      }
338  
339    if (!iface->setup())
340      {
341        // delete only this, not the whole stack.
342        dynamic_cast<LowLevelFilter *>(iface)->iface = nullptr;
343        return false;
344      }
345    return true;
346  }
347  
348  bool
349  USBDriver::setup ()
350  {
351    LowLevelDriver *orig_iface;
352  
353    version = cfgEMIVersion(cfg);
354    if (version == vERROR)
355      {
356        std::string v = cfg->value("version","");
357        ERRORPRINTF (t, E_ERROR | 56, "EMI version %s not recognized",v);
358        return false;
359      }
360  
361    if (iface != nullptr)
362      {
363        ERRORPRINTF (t, E_WARNING | 118, "interface in setup??");
364        delete iface;
365      }
366    usb_iface = new USBConverterInterface(this,cfg);
367    iface = usb_iface;
368    if (!iface->setup())
369      goto ex1;
370  
371    orig_iface = iface;
372    if(!make_EMI())
373      goto ex1;
374  
375    if (iface == nullptr)
376      iface = orig_iface;
377    if (!LowLevelAdapter::setup())
378      return false;
379    return true;
380  ex1:
381    delete iface;
382    iface = nullptr;
383    return false;
384  }
385