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