| 1 | /* ======================================================================== *\ | 
|---|
| 2 | ! | 
|---|
| 3 | ! * | 
|---|
| 4 | ! * This file is part of Stesy, the MAGIC Steering System | 
|---|
| 5 | ! * Software. It is distributed to you in the hope that it can be a useful | 
|---|
| 6 | ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. | 
|---|
| 7 | ! * It is distributed WITHOUT ANY WARRANTY. | 
|---|
| 8 | ! * | 
|---|
| 9 | ! * Permission to use, copy, modify and distribute this software and its | 
|---|
| 10 | ! * documentation for any purpose is hereby granted without fee, | 
|---|
| 11 | ! * provided that the above copyright notice appear in all copies and | 
|---|
| 12 | ! * that both that copyright notice and this permission notice appear | 
|---|
| 13 | ! * in supporting documentation. It is provided "as is" without express | 
|---|
| 14 | ! * or implied warranty. | 
|---|
| 15 | ! * | 
|---|
| 16 | ! | 
|---|
| 17 | ! | 
|---|
| 18 | !   Author(s): Thomas Bretz 2001 <mailto:tbretz@astro.uni-wuerzburg.de> | 
|---|
| 19 | ! | 
|---|
| 20 | !   Copyright: MAGIC Software Development, 2000-2008 | 
|---|
| 21 | ! | 
|---|
| 22 | ! | 
|---|
| 23 | \* ======================================================================== */ | 
|---|
| 24 |  | 
|---|
| 25 | /////////////////////////////////////////////////////////////////////// | 
|---|
| 26 | // | 
|---|
| 27 | // VmodIcan | 
|---|
| 28 | // | 
|---|
| 29 | // Class describing the interface to the Janz card in RawCan mode. | 
|---|
| 30 | // | 
|---|
| 31 | /////////////////////////////////////////////////////////////////////// | 
|---|
| 32 | #include "vmodican.h" | 
|---|
| 33 |  | 
|---|
| 34 | #include <fcntl.h>         // O_RDONLY | 
|---|
| 35 | #include <errno.h>         // errno | 
|---|
| 36 | #include <unistd.h>        // read | 
|---|
| 37 | #include <sys/time.h>      // gettimeofday | 
|---|
| 38 | #include <sys/ioctl.h>     // ioctl | 
|---|
| 39 |  | 
|---|
| 40 | #include "canopen.h" | 
|---|
| 41 |  | 
|---|
| 42 | #include "MLog.h" | 
|---|
| 43 | #include "MLogManip.h" | 
|---|
| 44 |  | 
|---|
| 45 | ClassImp(VmodIcan); | 
|---|
| 46 |  | 
|---|
| 47 | using namespace std; | 
|---|
| 48 |  | 
|---|
| 49 | // -------------------------------------------------------------------------- | 
|---|
| 50 | // | 
|---|
| 51 | // Embedded ioctl-function from C-lib | 
|---|
| 52 | // | 
|---|
| 53 | int VmodIcan::Ioctl(int msg, void *arg) | 
|---|
| 54 | { | 
|---|
| 55 | return fd<0 ? 1 : ioctl(fd, msg, arg) >= 0; | 
|---|
| 56 | } | 
|---|
| 57 |  | 
|---|
| 58 | // -------------------------------------------------------------------------- | 
|---|
| 59 | // | 
|---|
| 60 | // Enables/Disables the termination. | 
|---|
| 61 | // | 
|---|
| 62 | void VmodIcan::SetTermination(int state)  /* 0 = off, 1 = on */ | 
|---|
| 63 | { | 
|---|
| 64 | /* -*-Func-*- | 
|---|
| 65 | * | 
|---|
| 66 | * SwitchCanTermination - Switch the CANbus termination resistor | 
|---|
| 67 | * | 
|---|
| 68 | * The VMOD-ICAN3 module allows the user to change the state of the CANbus | 
|---|
| 69 | * termination via software. This is done with this service. | 
|---|
| 70 | * | 
|---|
| 71 | * SERVICE: HwConf | 
|---|
| 72 | */ | 
|---|
| 73 |  | 
|---|
| 74 | Message msg; | 
|---|
| 75 |  | 
|---|
| 76 | msg.cmd = M_HW_CONF; | 
|---|
| 77 |  | 
|---|
| 78 | msg.len = 2; | 
|---|
| 79 | msg.data[0] = 0x00; | 
|---|
| 80 | msg.data[1] = (BYTE_t)state; | 
|---|
| 81 |  | 
|---|
| 82 | while (!Send(&msg)); | 
|---|
| 83 |  | 
|---|
| 84 | gLog << inf2 << "- CAN Bus Termination set to " << (state?"on":"off") << endl; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | // -------------------------------------------------------------------------- | 
|---|
| 88 | // | 
|---|
| 89 | // Receiver Thread. Listener. Listens for incomming messages and processes | 
|---|
| 90 | // these messages through the standard interface: | 
|---|
| 91 | //  - therefor overload HandleCanMessge | 
|---|
| 92 | // | 
|---|
| 93 | Int_t VmodIcan::Thread() | 
|---|
| 94 | { | 
|---|
| 95 | if (fd<0) | 
|---|
| 96 | return 0; | 
|---|
| 97 |  | 
|---|
| 98 | gLog << inf2 << "- Starting Receiver Loop." << endl; | 
|---|
| 99 |  | 
|---|
| 100 | while (1) | 
|---|
| 101 | { | 
|---|
| 102 | // | 
|---|
| 103 | // Sleeps until a message arrives | 
|---|
| 104 | // | 
|---|
| 105 | TThread::CancelPoint(); | 
|---|
| 106 |  | 
|---|
| 107 | unsigned char c; | 
|---|
| 108 | const int n = read(fd, &c, 1); | 
|---|
| 109 |  | 
|---|
| 110 | TThread::CancelPoint(); | 
|---|
| 111 |  | 
|---|
| 112 | if (n<0) | 
|---|
| 113 | { | 
|---|
| 114 | cerr << "Vmodican: read(" << dec << (int)fd << "," << (void*)&c; | 
|---|
| 115 | cerr << ",1) returned rc=" << n << " c=" << (int)c << " '"; | 
|---|
| 116 | cerr << strerror(errno) << "' (errno = " << errno << ")" << endl; | 
|---|
| 117 | continue; | 
|---|
| 118 | } | 
|---|
| 119 |  | 
|---|
| 120 | // | 
|---|
| 121 | // if n==0 something strange happened. Stop receiver(?) | 
|---|
| 122 | // | 
|---|
| 123 | if (n == 0) | 
|---|
| 124 | { | 
|---|
| 125 | cerr << "Vmodican: Panic read '" << strerror(errno) << "' "; | 
|---|
| 126 | cerr << "(errno=" << errno << ")" << endl; | 
|---|
| 127 | return 1; | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // | 
|---|
| 131 | // Check for what we received | 
|---|
| 132 | // | 
|---|
| 133 | switch (c) | 
|---|
| 134 | { | 
|---|
| 135 | // | 
|---|
| 136 | // Fast message (not used/working) | 
|---|
| 137 | // | 
|---|
| 138 | /* | 
|---|
| 139 | case FAST_QUEUE: | 
|---|
| 140 | cout << "--> Fast Queue:  " << flush; | 
|---|
| 141 |  | 
|---|
| 142 | FastMessage fmsg; | 
|---|
| 143 |  | 
|---|
| 144 | if (ReceiveFast(&fmsg) < 0) | 
|---|
| 145 | return (void *)1; | 
|---|
| 146 |  | 
|---|
| 147 | cout << "Fast msg ID " << | 
|---|
| 148 | (fmsg.data[0] << 3) + ((fmsg.data[1] >> 5) & 7) << ": " << flush; | 
|---|
| 149 |  | 
|---|
| 150 | for(int i=0; i<16; i++) | 
|---|
| 151 | cout << (int)*(((unsigned char *)(&fmsg))+i) << " " << flush; | 
|---|
| 152 |  | 
|---|
| 153 | cout << endl; | 
|---|
| 154 | continue; | 
|---|
| 155 | */ | 
|---|
| 156 | // | 
|---|
| 157 | // Plain Can Message to be processed | 
|---|
| 158 | // | 
|---|
| 159 | case PLAIN_QUEUE: | 
|---|
| 160 |  | 
|---|
| 161 | Message msg; | 
|---|
| 162 |  | 
|---|
| 163 | // | 
|---|
| 164 | // Read the message from the card and process it | 
|---|
| 165 | // | 
|---|
| 166 | if (Receive(&msg) < 0) | 
|---|
| 167 | return 1; | 
|---|
| 168 |  | 
|---|
| 169 | HandleMessage(msg); | 
|---|
| 170 | continue; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | cout << "Vmodican: read, Message c=" << (int)c << " unknown." << endl; | 
|---|
| 174 | } | 
|---|
| 175 | return 0; | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | // -------------------------------------------------------------------------- | 
|---|
| 179 | // | 
|---|
| 180 | //  This is can_recv from the Janz software. | 
|---|
| 181 | // | 
|---|
| 182 | //  /* can_recv - receive a message from standard interface | 
|---|
| 183 | //   * | 
|---|
| 184 | //   * This function reads a whole message from the standard host interface of | 
|---|
| 185 | //   * a VMOD-ICAN. | 
|---|
| 186 | //   * The module is selected by the module number <fd>. | 
|---|
| 187 | //   * | 
|---|
| 188 | //   * The structure <pm> is filled with the received message. | 
|---|
| 189 | //   * | 
|---|
| 190 | //   * RETURNS: | 
|---|
| 191 | //   * The function returns the number of message received, or -1 when the | 
|---|
| 192 | //   * system call failed. | 
|---|
| 193 | //   * The return value therefore 0 determines, that no message was available to | 
|---|
| 194 | //   * be read: can_recv() does not block in such a case and therefore | 
|---|
| 195 | //   * can be used to poll a module for incoming messages. | 
|---|
| 196 | //   */ | 
|---|
| 197 | // | 
|---|
| 198 | int VmodIcan::Receive(Message *pm) /* receive buffer */ | 
|---|
| 199 | { | 
|---|
| 200 | struct dpm_rw_can_desc arg; | 
|---|
| 201 |  | 
|---|
| 202 | arg.pm = pm; | 
|---|
| 203 |  | 
|---|
| 204 | if (!Ioctl(DPM_READ_MBOX, &arg)) | 
|---|
| 205 | return -1; | 
|---|
| 206 |  | 
|---|
| 207 | return arg.rval; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | // -------------------------------------------------------------------------- | 
|---|
| 211 | // | 
|---|
| 212 | // This is can_recv_fast from the Janz software | 
|---|
| 213 | // | 
|---|
| 214 | //  /* can_recv_fast - receive a message from layer2 interface | 
|---|
| 215 | //   * | 
|---|
| 216 | //   * This function reads a FastMessage from the layer2 fast message | 
|---|
| 217 | //   * interface of a VMOD-ICAN. | 
|---|
| 218 | //   * The module is selected by the file descriptor <fd>. | 
|---|
| 219 | //   * | 
|---|
| 220 | //   * The structure <pm> is filled with the received message. | 
|---|
| 221 | //   * | 
|---|
| 222 | //   * RETURNS: | 
|---|
| 223 | //   * The function returns -1 when the * system call failed. | 
|---|
| 224 | //   * The return value therefore 0 determines, that no message was available to | 
|---|
| 225 | //   * be read: can_recv_fast() does not block in such a case and therefore | 
|---|
| 226 | //   * can be used to poll a module for incoming messages. | 
|---|
| 227 | //   */ | 
|---|
| 228 | /* | 
|---|
| 229 | int VmodIcan::ReceiveFast(FastMessage *pm) | 
|---|
| 230 | { | 
|---|
| 231 | struct dpm_write_fast_can_desc arg; | 
|---|
| 232 |  | 
|---|
| 233 | arg.pm = pm; | 
|---|
| 234 |  | 
|---|
| 235 | if (!Ioctl(DPM_READ_FAST_MBOX, &arg)) | 
|---|
| 236 | return -1; | 
|---|
| 237 |  | 
|---|
| 238 | return arg.rval; | 
|---|
| 239 | } | 
|---|
| 240 | */ | 
|---|
| 241 |  | 
|---|
| 242 | // -------------------------------------------------------------------------- | 
|---|
| 243 | // | 
|---|
| 244 | // This is IcWriteBtrBCAN from the Janz software | 
|---|
| 245 | // | 
|---|
| 246 | //  /* IcWriteBtrBCAN - Set bit timing parameters | 
|---|
| 247 | //   * | 
|---|
| 248 | //   * Set bit timing parameters in CAN controller. May only be used if | 
|---|
| 249 | //   * CAN controller is in bus-off state. <btr> stores the bus-timing | 
|---|
| 250 | //   * parameters as required by the 82C200 controller. See the description | 
|---|
| 251 | //   * of the CBTRreq-service for possible values. | 
|---|
| 252 | //   * | 
|---|
| 253 | //   * BTR1 is stored in the upper byte of <btr> and BTR0 in the lower. Examples | 
|---|
| 254 | //   * are: | 
|---|
| 255 | //   * .CS | 
|---|
| 256 | //   *     Baudrate   btr       Macro | 
|---|
| 257 | //   *       1Mbit    0x2300    BTR_1MB | 
|---|
| 258 | //   *     500kBit    0x1c00    BTR_500KB | 
|---|
| 259 | //   *     250kBit    0x1c01    BTR_250KB | 
|---|
| 260 | //   *     125kBit    0x1c03    BTR_125KB | 
|---|
| 261 | //   *     100kBit    0x34c7    BTR_100KB | 
|---|
| 262 | //   *      50kBit    0x34cf    BTR_50KB | 
|---|
| 263 | //   *      20kBit    0x7fcf    BTR_20KB | 
|---|
| 264 | //   * .CE | 
|---|
| 265 | //   * | 
|---|
| 266 | //   * SERVICE: CBTRreq | 
|---|
| 267 | //   * | 
|---|
| 268 | //   * NOTE: | 
|---|
| 269 | //   * Raw ICANOS version of the firmware only. | 
|---|
| 270 | //   */ | 
|---|
| 271 | // | 
|---|
| 272 | void VmodIcan::SetBaudRate(int rate) | 
|---|
| 273 | { | 
|---|
| 274 | Message msg;  /* buffer for module messages */ | 
|---|
| 275 |  | 
|---|
| 276 | int rateid; | 
|---|
| 277 |  | 
|---|
| 278 | switch (rate) | 
|---|
| 279 | { | 
|---|
| 280 | case 1000: | 
|---|
| 281 | rateid=BTR_1MB; | 
|---|
| 282 | break; | 
|---|
| 283 | case  500: | 
|---|
| 284 | rateid=BTR_500KB; | 
|---|
| 285 | break; | 
|---|
| 286 | case  250: | 
|---|
| 287 | rateid=BTR_250KB; | 
|---|
| 288 | break; | 
|---|
| 289 | case  125: | 
|---|
| 290 | rateid=BTR_125KB; | 
|---|
| 291 | break; | 
|---|
| 292 | case  100: | 
|---|
| 293 | rateid=BTR_100KB; | 
|---|
| 294 | break; | 
|---|
| 295 | case   50: | 
|---|
| 296 | rateid=BTR_50KB; | 
|---|
| 297 | break; | 
|---|
| 298 | case   20: | 
|---|
| 299 | rateid=BTR_20KB; | 
|---|
| 300 | break; | 
|---|
| 301 |  | 
|---|
| 302 | default: | 
|---|
| 303 | cout << "Error: Wrong bit rate specified" << endl; | 
|---|
| 304 | return; | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | msg.cmd = M_BCAN_SET_BTR_req; | 
|---|
| 308 |  | 
|---|
| 309 | msg.len = 4; | 
|---|
| 310 |  | 
|---|
| 311 | msg.data[2] = word_to_lsb(rateid); | 
|---|
| 312 | msg.data[3] = word_to_msb(rateid); | 
|---|
| 313 |  | 
|---|
| 314 | while (!Send(&msg));      /* transmitt to module */ | 
|---|
| 315 |  | 
|---|
| 316 | gLog << inf2 << "- Baudrate set to " << rate << "kbps" << endl; | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | // -------------------------------------------------------------------------- | 
|---|
| 320 | // | 
|---|
| 321 | // This is IcBusOnBCAN from the Janz software | 
|---|
| 322 | // | 
|---|
| 323 | //  /* IcBusOnBCAN - switch CANbus controller to bus-on state | 
|---|
| 324 | //   * | 
|---|
| 325 | //   * Switch CAN controller bus-on. You will need to use this | 
|---|
| 326 | //   * function explicitly after you have connected yourself | 
|---|
| 327 | //   * to the module with can_open() (or ican_open() under DOS/WINDOWS). | 
|---|
| 328 | //   * This is because the module comes up in the bus-off state. | 
|---|
| 329 | //   * | 
|---|
| 330 | //   * SERVICE: CONreq | 
|---|
| 331 | //   * | 
|---|
| 332 | //   * NOTE: | 
|---|
| 333 | //   * Raw ICANOS version of the firmware only. | 
|---|
| 334 | //   */ | 
|---|
| 335 | // | 
|---|
| 336 | void VmodIcan::EnableCanBusConnection() | 
|---|
| 337 | { | 
|---|
| 338 | Message msg;                  /* buffer for module messages */ | 
|---|
| 339 |  | 
|---|
| 340 | msg.cmd = M_BCAN_BUSON_req; | 
|---|
| 341 | msg.len = 0; | 
|---|
| 342 |  | 
|---|
| 343 | while (!Send(&msg)); | 
|---|
| 344 |  | 
|---|
| 345 | gLog << inf2 << "- Controller connected to bus" << endl; | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | // -------------------------------------------------------------------------- | 
|---|
| 349 | // | 
|---|
| 350 | // This is ican2_init_fast_canfrom the Janz software | 
|---|
| 351 | // | 
|---|
| 352 | //  /* ican2_init_fast_can - initialize fast can access for VMOD-ICAN | 
|---|
| 353 | //   * | 
|---|
| 354 | //   * By this function, the user may initialize and enable the fast | 
|---|
| 355 | //   * host interface (layer2 access) for a VMOD-ICAN module. | 
|---|
| 356 | //   * | 
|---|
| 357 | //   * The calling application can request <rbuffers> buffer elements in the queue | 
|---|
| 358 | //   * that sends data to the host and <wbuffers> buffer elements for the queue | 
|---|
| 359 | //   * that transports data to the module. | 
|---|
| 360 | //   * | 
|---|
| 361 | //   * NOTE: | 
|---|
| 362 | //   * Notice that the message filtering on the VMOD-ICAN has to be | 
|---|
| 363 | //   * set correctly, so that messages can be received through the fast | 
|---|
| 364 | //   * interface. | 
|---|
| 365 | //   * | 
|---|
| 366 | //   * CAVE AT: | 
|---|
| 367 | //   * The <rbuffers> and wbuffers> have no special limit, but the general | 
|---|
| 368 | //   * resources of the DPM must not be exceeded. | 
|---|
| 369 | //   * For the calculation you need to assume, that 16 buffers in one of the fast | 
|---|
| 370 | //   * interface queues take the same DPM space as 1 buffer in the standard | 
|---|
| 371 | //   * host interface. | 
|---|
| 372 | //   * | 
|---|
| 373 | //   * The user must use only one of the functions, either | 
|---|
| 374 | //   * ican2_init_fast_can or ican2_init_fast_can_prio | 
|---|
| 375 | //   * | 
|---|
| 376 | //   * RETURNS: | 
|---|
| 377 | //   * Zero if the operation performed successfully, or less than zero on error. | 
|---|
| 378 | //   */ | 
|---|
| 379 | // | 
|---|
| 380 | int VmodIcan::EnableFastCan(int rbuffers, int wbuffers) | 
|---|
| 381 | { | 
|---|
| 382 | struct dpm_fast_can_desc hdp; | 
|---|
| 383 |  | 
|---|
| 384 | hdp.tohost_len   = rbuffers; | 
|---|
| 385 | hdp.fromhost_len = wbuffers; | 
|---|
| 386 |  | 
|---|
| 387 | if (!Ioctl(DPM_INIT_FAST_CAN, &hdp)) | 
|---|
| 388 | return -1; | 
|---|
| 389 |  | 
|---|
| 390 | gLog << inf2 << "- Fast Host Interface Enabled" << endl; | 
|---|
| 391 |  | 
|---|
| 392 | return 0; | 
|---|
| 393 | } | 
|---|
| 394 |  | 
|---|
| 395 | // -------------------------------------------------------------------------- | 
|---|
| 396 | // | 
|---|
| 397 | // This is IcWriteEwlBCAN from the Janz software | 
|---|
| 398 | // | 
|---|
| 399 | //  /* IcWriteEwlBCAN - Set error warning limit | 
|---|
| 400 | //   * | 
|---|
| 401 | //   * Set error warning limit in CAN controller. If this limit is passed, the | 
|---|
| 402 | //   * user will get a CEVTind message stating an error interrupt. This type | 
|---|
| 403 | //   * of message will also occur if the both error counter again fall below | 
|---|
| 404 | //   * this limit. | 
|---|
| 405 | //   * | 
|---|
| 406 | //   * RESTRICTIONS: | 
|---|
| 407 | //   * Will only take effect if CAN controller is in bus-off state. Requires | 
|---|
| 408 | //   * an SJA1000 CANbus controller, and will be no-op for 82C200. | 
|---|
| 409 | //   * | 
|---|
| 410 | //   * SERVICE: CBCONFreq | 
|---|
| 411 | //   * | 
|---|
| 412 | //   * NOTE: | 
|---|
| 413 | //   * Raw ICANOS version of the firmware only. | 
|---|
| 414 | //   */ | 
|---|
| 415 | // | 
|---|
| 416 | void VmodIcan::DisableCanBusConnection() | 
|---|
| 417 | { | 
|---|
| 418 | gLog << inf2 << "- Disconnect VmodIcan module from Bus!" << endl; | 
|---|
| 419 |  | 
|---|
| 420 | Message msg;                  /* buffer for module messages */ | 
|---|
| 421 |  | 
|---|
| 422 | msg.cmd = M_BCAN_BUSOFF_req; | 
|---|
| 423 | msg.len = 0; | 
|---|
| 424 |  | 
|---|
| 425 | while (!Send(&msg)); | 
|---|
| 426 |  | 
|---|
| 427 | gLog << inf2 << "- VmodIcan disconnected." << endl; | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 | // -------------------------------------------------------------------------- | 
|---|
| 431 | // | 
|---|
| 432 | // This is can_close from the Janz software | 
|---|
| 433 | // | 
|---|
| 434 | //  /* can_close - close connection to a VMOD-ICAN module | 
|---|
| 435 | //   * | 
|---|
| 436 | //   * The function can be used to close a connection to a VMOD-ICAN | 
|---|
| 437 | //   * that has been established by a can_open() call. | 
|---|
| 438 | //   * The module has to be selected by the file descriptor <fd> which was | 
|---|
| 439 | //   * obtained when you did the can_open() call. | 
|---|
| 440 | //   * | 
|---|
| 441 | //   * When you call can_close, all the resources that were used by the driver | 
|---|
| 442 | //   * for communication are freed. | 
|---|
| 443 | //   * | 
|---|
| 444 | //   * The VMOD-ICAN module under question will be reseted, to make sure that | 
|---|
| 445 | //   * the communication with the host will stop. That means especially that | 
|---|
| 446 | //   * no further interrupt will occur and that the module will not longer be | 
|---|
| 447 | //   * active on the CANbus. | 
|---|
| 448 | //   * | 
|---|
| 449 | //   * RETURNS: N/A | 
|---|
| 450 | //   */ | 
|---|
| 451 | // | 
|---|
| 452 | void VmodIcan::Close() | 
|---|
| 453 | { | 
|---|
| 454 | gLog << inf2 << "- Closing device VmodIcan #" << (int)fd << endl; | 
|---|
| 455 |  | 
|---|
| 456 | Message msg; /* disconnect message */ | 
|---|
| 457 |  | 
|---|
| 458 | msg.cmd = M_DISCONNECT; | 
|---|
| 459 | msg.len = 0; | 
|---|
| 460 |  | 
|---|
| 461 | while (!Send(&msg)); | 
|---|
| 462 |  | 
|---|
| 463 | close(fd); | 
|---|
| 464 |  | 
|---|
| 465 | gLog << inf2 << "- Device closed." << endl; | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|
| 468 | // -------------------------------------------------------------------------- | 
|---|
| 469 | // | 
|---|
| 470 | // Enable the fifo of the Janz card | 
|---|
| 471 | // Allow VMOD to send messages through the fifo | 
|---|
| 472 | // | 
|---|
| 473 | int VmodIcan::EnableFifo() | 
|---|
| 474 | { | 
|---|
| 475 | Message msg; /* connect message */ | 
|---|
| 476 |  | 
|---|
| 477 | msg.cmd = M_CONNECT_INTR; | 
|---|
| 478 | msg.len = 0; | 
|---|
| 479 |  | 
|---|
| 480 | while (!Send(&msg)); | 
|---|
| 481 |  | 
|---|
| 482 | gLog << inf2 << "- Fifo enabled" << endl; | 
|---|
| 483 |  | 
|---|
| 484 | return TRUE; | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | // -------------------------------------------------------------------------- | 
|---|
| 488 | // | 
|---|
| 489 | // Reset the module | 
|---|
| 490 | // | 
|---|
| 491 | int VmodIcan::Reset() | 
|---|
| 492 | { | 
|---|
| 493 | const int rc = Ioctl(DPM_RESET, 0); | 
|---|
| 494 |  | 
|---|
| 495 | gLog << inf2 << "- Reset done." << endl; | 
|---|
| 496 |  | 
|---|
| 497 | return rc; | 
|---|
| 498 | } | 
|---|
| 499 |  | 
|---|
| 500 | // -------------------------------------------------------------------------- | 
|---|
| 501 | // | 
|---|
| 502 | // This is can_open from the Janz software | 
|---|
| 503 | // | 
|---|
| 504 | //  /* can_open - open VMOD-ICAN device | 
|---|
| 505 | //   * | 
|---|
| 506 | //   * With this function call you open a VMOD-ICAN plugged | 
|---|
| 507 | //   * into a MODULbus carrier board for use. The module is | 
|---|
| 508 | //   * reseted and then initialized for communication to the host. | 
|---|
| 509 | //   * | 
|---|
| 510 | //   * A specific module is selected by it's device name (e.g. "/dev/dpm_01"). | 
|---|
| 511 | //   */ | 
|---|
| 512 | // | 
|---|
| 513 | int VmodIcan::Open(const char *devname)          /* pathname of device */ | 
|---|
| 514 | { | 
|---|
| 515 | fd = open(devname, O_RDONLY, 0); | 
|---|
| 516 |  | 
|---|
| 517 | if (fd < 0) | 
|---|
| 518 | { | 
|---|
| 519 | gLog << err << "Error: Opening device '" << devname << "' (rc=" << fd << ")" << endl; | 
|---|
| 520 | gLog << strerror(errno) << endl; | 
|---|
| 521 | return FALSE; | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|
| 524 | gLog << inf << "- Device " << devname << " #" << fd << " open." << endl; | 
|---|
| 525 |  | 
|---|
| 526 | return TRUE; | 
|---|
| 527 | } | 
|---|
| 528 |  | 
|---|
| 529 | // -------------------------------------------------------------------------- | 
|---|
| 530 | // | 
|---|
| 531 | // This is ican2_select_hostif from the Janz software | 
|---|
| 532 | // | 
|---|
| 533 | //  /* ican2_select_hostif - switch standard host interface to new style mode | 
|---|
| 534 | //   * | 
|---|
| 535 | //   * The routine ican2_select_hostif() can be used to switch a module from | 
|---|
| 536 | //   * the standard host interface to the new style mode. The module is selected | 
|---|
| 537 | //   * by the module number <fd>. | 
|---|
| 538 | //   * | 
|---|
| 539 | //   * The calling application can request <rbuffers> buffer for the communication | 
|---|
| 540 | //   * queue that sends data to the host and <wbuffers> buffer for the reverse | 
|---|
| 541 | //   * communication direction (normal priority queue). By this function the hi- and | 
|---|
| 542 | //   * low-prioritized message-queues which sends data to the module are initialized | 
|---|
| 543 | //   * to a length of 1. | 
|---|
| 544 | //   * | 
|---|
| 545 | //   * NOTE: | 
|---|
| 546 | //   * To notify the module of the new situation, the driver sends | 
|---|
| 547 | //   * a M_NEWHOSTIF message to the module. This is the last message to be | 
|---|
| 548 | //   * transfered through the old style host interface. Immediately after | 
|---|
| 549 | //   * sending this message, the library is switched to the new style mode. | 
|---|
| 550 | //   * Any messages that are sent by the module in this time gap, may be lost. | 
|---|
| 551 | //   * It is therefore not recommended to use this function when you wait | 
|---|
| 552 | //   * for messages from the module. | 
|---|
| 553 | //   * | 
|---|
| 554 | //   * The selection of the new host interface is not reversible. It will stay | 
|---|
| 555 | //   * until the next reset for the module occurs. This will probably occur | 
|---|
| 556 | //   * when you use can_close(). | 
|---|
| 557 | //   * | 
|---|
| 558 | //   * HINTS: | 
|---|
| 559 | //   * When the new style mode is active, no more internal message buffering | 
|---|
| 560 | //   * on the module exists. That is whenever the module tries to send something | 
|---|
| 561 | //   * and cannot because the queue is full, this message will be dropped. | 
|---|
| 562 | //   * Thereby, when enabling the new style host interface you should create | 
|---|
| 563 | //   * enough buffers for the queue that sends to the host, to prevent the | 
|---|
| 564 | //   * loss of messages. If you loose messages, however you will be indicated | 
|---|
| 565 | //   * of that event by a MSGLOST messages (which will not be lost!). | 
|---|
| 566 | //   * | 
|---|
| 567 | //   * CAVE AT: | 
|---|
| 568 | //   * The parameters <rbuffers>, <wbuffers>, <wbuffers_hi> and <wbuffers_low> | 
|---|
| 569 | //   * must be greater than 0, less than 128, and the total sum must not | 
|---|
| 570 | //   * exceed 236. These parameters aren't checked by the driver! | 
|---|
| 571 | //   */ | 
|---|
| 572 | // | 
|---|
| 573 | int VmodIcan::StdHost2NewStyle(int rbuffers, int wbuffers, | 
|---|
| 574 | int wbuffers_hi, int wbuffers_low) | 
|---|
| 575 | { | 
|---|
| 576 | struct dpm_new_hostif_desc_prio hdp; | 
|---|
| 577 |  | 
|---|
| 578 | hdp.tohost_len       = rbuffers; | 
|---|
| 579 | hdp.fromhost_len     = wbuffers; | 
|---|
| 580 | hdp.fromhost_hi_len  = wbuffers_hi; | 
|---|
| 581 | hdp.fromhost_low_len = wbuffers_low; | 
|---|
| 582 |  | 
|---|
| 583 | Ioctl(DPM_INIT_NEW_HOSTIF_PRIO, &hdp); | 
|---|
| 584 |  | 
|---|
| 585 | gLog << inf2 << "- New style host interface enabled" << endl; | 
|---|
| 586 |  | 
|---|
| 587 | return 0; | 
|---|
| 588 | } | 
|---|
| 589 |  | 
|---|
| 590 | // -------------------------------------------------------------------------- | 
|---|
| 591 | // | 
|---|
| 592 | // This is can_send_hi from the Janz software | 
|---|
| 593 | // | 
|---|
| 594 | //  /* can_send_hi - send message to standard host interface (high priority) | 
|---|
| 595 | //   * | 
|---|
| 596 | //   * This function performs the same action as can_send(), except it will | 
|---|
| 597 | //   * append message <pm> to the highest priority queue of the standard | 
|---|
| 598 | //   * host interface. | 
|---|
| 599 | //   * | 
|---|
| 600 | //   * NOTE: | 
|---|
| 601 | //   * Notice that the prioritized issue of the message take effect on the new style | 
|---|
| 602 | //   * mode of the standard host interface only. | 
|---|
| 603 | //   * | 
|---|
| 604 | //   * RETURNS: | 
|---|
| 605 | //   * The function returns the number of message send, or -1 when the system | 
|---|
| 606 | //   * call failed. | 
|---|
| 607 | //   * The return value 0 determines that no message could be send, | 
|---|
| 608 | //   * probably because there was no space in the targeted queue. can_send_hi() | 
|---|
| 609 | //   * does not block or retry in such a case, so you need to loop explicitly | 
|---|
| 610 | //   * until the message is send. | 
|---|
| 611 | //   */ | 
|---|
| 612 | // | 
|---|
| 613 | /* | 
|---|
| 614 | int VmodIcan::SendHi(Message *pm) | 
|---|
| 615 | { | 
|---|
| 616 | struct dpm_rw_can_desc arg; | 
|---|
| 617 |  | 
|---|
| 618 | arg.pm = pm; | 
|---|
| 619 |  | 
|---|
| 620 | if (!Ioctl(DPM_WRITE_MBOX_HI, &arg)) | 
|---|
| 621 | return FALSE; | 
|---|
| 622 |  | 
|---|
| 623 | return arg.rval; | 
|---|
| 624 | } | 
|---|
| 625 | */ | 
|---|
| 626 |  | 
|---|
| 627 | // -------------------------------------------------------------------------- | 
|---|
| 628 | // | 
|---|
| 629 | // This is can_send_low from the Janz software | 
|---|
| 630 | // | 
|---|
| 631 | //  /* can_send_low - send message to standard host interface (low priority) | 
|---|
| 632 | //   * | 
|---|
| 633 | //   * This function performs the same action as can_send(), except it will | 
|---|
| 634 | //   * append message <pm> to the lowest priority queue of the standard | 
|---|
| 635 | //   * host interface. | 
|---|
| 636 | //   * | 
|---|
| 637 | //   * NOTE: | 
|---|
| 638 | //   * Notice that the prioritized issue of the message take effect on the new | 
|---|
| 639 | //   * style mode of the standard host interface only. | 
|---|
| 640 | //   * | 
|---|
| 641 | //   * RETURNS: | 
|---|
| 642 | //   * The function returns the number of message send, or -1 when the system | 
|---|
| 643 | //   * call failed. | 
|---|
| 644 | //   * The return value 0 determines that no message could be send, | 
|---|
| 645 | //   * probably because there was no space in the targeted queue. can_send_low() | 
|---|
| 646 | //   * does not block or retry in such a case, so you need to loop explicitly | 
|---|
| 647 | //   * until the message is send. | 
|---|
| 648 | //   * | 
|---|
| 649 | //   */ | 
|---|
| 650 | /* | 
|---|
| 651 | int VmodIcan::SendLo(Message *pm) | 
|---|
| 652 | { | 
|---|
| 653 | struct dpm_rw_can_desc arg; | 
|---|
| 654 |  | 
|---|
| 655 | arg.pm = pm; | 
|---|
| 656 |  | 
|---|
| 657 | if (!Ioctl(DPM_WRITE_MBOX_LOW, &arg)) | 
|---|
| 658 | return FALSE; | 
|---|
| 659 |  | 
|---|
| 660 | return arg.rval; | 
|---|
| 661 | } | 
|---|
| 662 | */ | 
|---|
| 663 |  | 
|---|
| 664 | // -------------------------------------------------------------------------- | 
|---|
| 665 | // | 
|---|
| 666 | // This is can_send from the Janz software | 
|---|
| 667 | // | 
|---|
| 668 | //  /* can_send - send message to standard host interface (mid priority) | 
|---|
| 669 | //   * | 
|---|
| 670 | //   * This function sends a complete message to the standard host interface | 
|---|
| 671 | //   * of a VMOD-ICAN. | 
|---|
| 672 | //   * | 
|---|
| 673 | //   * The message <pm> will be queued to the middle prioritized of the three | 
|---|
| 674 | //   * queues. | 
|---|
| 675 | //   * | 
|---|
| 676 | //   * RETURNS: | 
|---|
| 677 | //   * The function returns the number of message send, or -1 when the system | 
|---|
| 678 | //   * call failed. | 
|---|
| 679 | //   * The return value 0 determines that no message could be send, | 
|---|
| 680 | //   * probably because there was no space in the targeted queue. can_send() | 
|---|
| 681 | //   * does not block or retry in such a case, so you need to loop explicitly | 
|---|
| 682 | //   * until the message is send. | 
|---|
| 683 | //   */ | 
|---|
| 684 | // | 
|---|
| 685 | int VmodIcan::Send(Message *pm) /* file descriptor, message to send */ | 
|---|
| 686 | { | 
|---|
| 687 | struct dpm_rw_can_desc arg; | 
|---|
| 688 |  | 
|---|
| 689 | arg.pm = pm; | 
|---|
| 690 |  | 
|---|
| 691 | return Ioctl(DPM_WRITE_MBOX, &arg) ? arg.rval : 0; | 
|---|
| 692 | } | 
|---|
| 693 |  | 
|---|
| 694 | // -------------------------------------------------------------------------- | 
|---|
| 695 | // | 
|---|
| 696 | // This is can_fast_send from the Janz software | 
|---|
| 697 | // | 
|---|
| 698 | //  /* can_fast_send - send message to fast interface | 
|---|
| 699 | //   * | 
|---|
| 700 | //   * This function sends a message to the fast host interface (layer-2 | 
|---|
| 701 | //   * interface) of a VMOD-ICAN. The module is selected by the module number | 
|---|
| 702 | //   * <fd>. | 
|---|
| 703 | //   * The message to be send will be given in the structure <pm>. | 
|---|
| 704 | //   * | 
|---|
| 705 | //   * The fast host interface needs to be established before can_fast_send() | 
|---|
| 706 | //   * can be used successfully. | 
|---|
| 707 | //   * | 
|---|
| 708 | //   * RETURNS: | 
|---|
| 709 | //   * The function returns 1 if can_fast_send() completed successful. | 
|---|
| 710 | //   * Otherwise the return value 0 determines that the message could not be send, | 
|---|
| 711 | //   * probably because there was no space in the DPM. The function | 
|---|
| 712 | //   * does not block or retry in such a case, so you need to loop explicitly | 
|---|
| 713 | //   * until the message is send. | 
|---|
| 714 | //   * The function returns -1 when the system-call itself failed. | 
|---|
| 715 | //   */ | 
|---|
| 716 | // | 
|---|
| 717 | /* | 
|---|
| 718 | int VmodIcan::Send(FastMessage *pm) | 
|---|
| 719 | { | 
|---|
| 720 | struct dpm_write_fast_can_desc arg; | 
|---|
| 721 |  | 
|---|
| 722 | arg.pm = pm; | 
|---|
| 723 |  | 
|---|
| 724 | if (!Ioctl(DPM_WRITE_FAST_CAN, &arg)) | 
|---|
| 725 | return FALSE; | 
|---|
| 726 |  | 
|---|
| 727 | gLog << "done." << endl; | 
|---|
| 728 |  | 
|---|
| 729 | return arg.rval; | 
|---|
| 730 | } | 
|---|
| 731 | */ | 
|---|
| 732 |  | 
|---|
| 733 | // -------------------------------------------------------------------------- | 
|---|
| 734 | // | 
|---|
| 735 | // This is IcSetAfil from the Janz software | 
|---|
| 736 | // | 
|---|
| 737 | //  /* | 
|---|
| 738 | //   * IcSetAfil - Set software acceptance filter mask | 
|---|
| 739 | //   * | 
|---|
| 740 | //   * Set software acceptance filtering. | 
|---|
| 741 | //   * | 
|---|
| 742 | //   * SERVICE: SetAfilMask | 
|---|
| 743 | //   */ | 
|---|
| 744 | // | 
|---|
| 745 | void VmodIcan::DisableAllCobIds() | 
|---|
| 746 | { | 
|---|
| 747 | Message msg; | 
|---|
| 748 |  | 
|---|
| 749 | msg.cmd = M_SET_AFIL; | 
|---|
| 750 | msg.len = 5; | 
|---|
| 751 |  | 
|---|
| 752 | msg.data[0]  = word_to_lsb(0); | 
|---|
| 753 | msg.data[1]  = word_to_msb(0); | 
|---|
| 754 | msg.data[2]  = word_to_lsb(0x7ff); // 11 bit Cob-Ids | 
|---|
| 755 | msg.data[3]  = word_to_msb(0x7ff); // 11 bit Cob-Ids | 
|---|
| 756 | msg.data[4]  = 0; | 
|---|
| 757 |  | 
|---|
| 758 | while (!Send(&msg)); | 
|---|
| 759 |  | 
|---|
| 760 | gLog << inf2 << "- All CobIds disabled." << endl; | 
|---|
| 761 | } | 
|---|
| 762 |  | 
|---|
| 763 | // -------------------------------------------------------------------------- | 
|---|
| 764 | // | 
|---|
| 765 | // This is IcSetAfil from the Janz software | 
|---|
| 766 | // | 
|---|
| 767 | //  /* | 
|---|
| 768 | //   * IcSetAfil - Set software acceptance filter mask | 
|---|
| 769 | //   * | 
|---|
| 770 | //   * Set software acceptance filtering. | 
|---|
| 771 | //   * | 
|---|
| 772 | //   * SERVICE: SetAfilMask | 
|---|
| 773 | //   */ | 
|---|
| 774 | // | 
|---|
| 775 | void VmodIcan::EnableCobId(WORD_t cobid, int flag) | 
|---|
| 776 | { | 
|---|
| 777 | Message msg; | 
|---|
| 778 |  | 
|---|
| 779 | msg.cmd = M_SET_AFIL; | 
|---|
| 780 | msg.len = 3; | 
|---|
| 781 |  | 
|---|
| 782 | msg.data[0]  = word_to_lsb(cobid); | 
|---|
| 783 | msg.data[1]  = word_to_msb(cobid); | 
|---|
| 784 | msg.data[2]  = (BYTE_t)(flag?3:0); | 
|---|
| 785 |  | 
|---|
| 786 | while (!Send(&msg)); | 
|---|
| 787 | #ifdef EXPERT | 
|---|
| 788 | gLog << "- CobId 0x" << hex << setfill('0') << setw(3) << cobid << " enabled." << endl; | 
|---|
| 789 | #endif | 
|---|
| 790 | } | 
|---|
| 791 |  | 
|---|
| 792 | // -------------------------------------------------------------------------- | 
|---|
| 793 | // | 
|---|
| 794 | // This is IcSendReqBCAN from the Janz software | 
|---|
| 795 | // | 
|---|
| 796 | //  /* | 
|---|
| 797 | //   * IcSendReqBCAN - Send a CANbus message | 
|---|
| 798 | //   * | 
|---|
| 799 | //   * Issue request to send a CAN message. <Spec> controls whether to send with | 
|---|
| 800 | //   * or without spec/confirmation. | 
|---|
| 801 | //   * .CS | 
|---|
| 802 | //   *    spec     action | 
|---|
| 803 | //   *      0      send only | 
|---|
| 804 | //   *      1      send with confirmation to the host. | 
|---|
| 805 | //   *      2      send and echo message to the host. | 
|---|
| 806 | //   *      3      send and generate both echo and confirmation. | 
|---|
| 807 | //   * .CE | 
|---|
| 808 | //   * | 
|---|
| 809 | //   * SERVICE: CTXreq, CTXCreq, CTXEreq, CTXCEreq | 
|---|
| 810 | //   * | 
|---|
| 811 | //   * NOTE: | 
|---|
| 812 | //   * Raw ICANOS version of the firmware only. | 
|---|
| 813 | //   */ | 
|---|
| 814 | // | 
|---|
| 815 | void VmodIcan::SendCanFrame(WORD_t cobid, BYTE_t m[8], BYTE_t rtr) | 
|---|
| 816 | { | 
|---|
| 817 | const WORD_t desc = MsgDescr(cobid, 8, rtr); | 
|---|
| 818 |  | 
|---|
| 819 | Message msg; | 
|---|
| 820 |  | 
|---|
| 821 | msg.cmd = M_BCAN_TX_req; | 
|---|
| 822 |  | 
|---|
| 823 | msg.len = 12; | 
|---|
| 824 | msg.data[0]  = 0; | 
|---|
| 825 | msg.data[1]  = 0; | 
|---|
| 826 | msg.data[2]  = word_to_msb(desc); | 
|---|
| 827 | msg.data[3]  = word_to_lsb(desc); | 
|---|
| 828 |  | 
|---|
| 829 | memcpy(&msg.data[4], m, 8); | 
|---|
| 830 |  | 
|---|
| 831 | while (!Send(&msg)); | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | // -------------------------------------------------------------------------- | 
|---|
| 835 | // | 
|---|
| 836 | // Constructor. Sets logging. | 
|---|
| 837 | //  Set the receiving thread to priority -10 and detached. | 
|---|
| 838 | // | 
|---|
| 839 | //  Open the device. | 
|---|
| 840 | //  reset the device | 
|---|
| 841 | //  Enable the fifo buffers | 
|---|
| 842 | //  Set the baud rate to the given rate | 
|---|
| 843 | //  Disable passthrough of all cobids (all canbus messages) | 
|---|
| 844 | //  and switch the can bus communication on | 
|---|
| 845 | // | 
|---|
| 846 | VmodIcan::VmodIcan(CanOpen *rx, const char *dev, const int baud) : Interface(rx) | 
|---|
| 847 | { | 
|---|
| 848 | // | 
|---|
| 849 | // Set priority of receiving thread and detach the receiving thread | 
|---|
| 850 | // | 
|---|
| 851 | //    Detach(); | 
|---|
| 852 |  | 
|---|
| 853 | if (!Open(dev)) | 
|---|
| 854 | { | 
|---|
| 855 | cout << "Cannot open device '" << dev << "'... exit." << endl; | 
|---|
| 856 | cout << strerror(errno) << endl; | 
|---|
| 857 | return; | 
|---|
| 858 | } | 
|---|
| 859 |  | 
|---|
| 860 | Reset(); | 
|---|
| 861 | EnableFifo();                      // connect to host (in interrupt mode) | 
|---|
| 862 | SetBaudRate(baud);                 // set baud rate | 
|---|
| 863 | DisableAllCobIds(); | 
|---|
| 864 | EnableCanBusConnection();          // connect to bus | 
|---|
| 865 | /* | 
|---|
| 866 | StdHost2NewStyle(50, 50, 50, 50);  // set host style | 
|---|
| 867 | EnableFastCan(50, 50); | 
|---|
| 868 | SetTermination(0); | 
|---|
| 869 | */ | 
|---|
| 870 |  | 
|---|
| 871 | gLog << inf << "- VmodIcan initialized." << endl; | 
|---|
| 872 |  | 
|---|
| 873 | } | 
|---|
| 874 |  | 
|---|
| 875 | // -------------------------------------------------------------------------- | 
|---|
| 876 | // | 
|---|
| 877 | // Destructor. Stopt the receiver, disables the bus connection and | 
|---|
| 878 | // close the device | 
|---|
| 879 | // | 
|---|
| 880 | VmodIcan::~VmodIcan() | 
|---|
| 881 | { | 
|---|
| 882 | gLog << inf2 << "- Stopping VmodIcan module." << endl; | 
|---|
| 883 | CancelThread(); | 
|---|
| 884 | DisableCanBusConnection(); | 
|---|
| 885 | Close(); | 
|---|
| 886 | gLog << inf << "- VmodIcan stopped." << endl; | 
|---|
| 887 | } | 
|---|