:!:This information is old or obsolete. See specification.

How to interface the daemon

Let me first start out by trying to explain how I try to deal with this situation (I have for instance 1-Wire, serial, RS-485 and other devices around the house). This is of course just one way of doing it and nothing I want to pack on to you or anyone else.

I think of the VSCP events as the common format (intermediate format if you like). So if I get a temperature or other measurement or whatever, I try to convert it as soon as possible into a VSCP event. When this is done it's got a “standard format” which can be:

  • read by other low end devices. Possible through another conversion step.
  • be logged into a database in a common format.
  • be translated info an action or something else.

A typical example is the OWW wather station software or the DigiTemp temperature software. Readings from the connected instrument are converted to VSCP events. Same for LIRC which take sin IR code.

As soon as this has been done and possible been feed to the daemon all the tools are available to play with the data. CanalWorks can be used to look at the data and simulated events, The ActiveX controls can be used to program stuff in C# and VB etc. The dll's and the classes can be used to program the stuff from other languages. The swig interfaces allow direct Perl, Java, C# and python interfacing. All this being ready available.

And now the big plus. Everything you do from this point is generally usable. If you do something that logs temperatures in a database at this point it works for all temperature sensors (your own, My Kelvin modules, DigiTemp, OWW etc etc) not only the one you developed.

Now to the question. ;-)

The daemon has several ways to talk to you.

  • UDP datagrams (Level II - but its OK to send Level I in Level II CLASS=512 …).
  • TCP/IP interface.
  • Direct interface (shared memory == very fast).
  • Canal daemon driver interface.

UDP interface

Two daemons can connect with each other through this interface. So if you have one daemon on a Linux machine and one on a Windows machine VSCP events will be available on both. You can of course send your own UDP datagrams (I think Charles has done this). Just broadcast in port 9598. Format is here
http://www.vscp.org/wiki/doku.php?id=vscp_specification_-_vscp_level_ii_over_tcp_ip.

TCP/IP interface

Also documented here http://www.vscp.org/wiki/doku.php?id=vscp_specification_-_vscp_level_ii_over_tcp_ip.
Samples here http://www.vscp.org/wiki/doku.php?id=howtos.

There is a class

CanalTcpIf

available in the src/canal/common folder that encapsulate the communication with the daemon TCP/IP interface. A sample application testtcpinterface in the /src/canal/testtcpinterface shows how it is used. A simple example on how to use this class looks like this

  CanalTcpIf tcpif;
 
  // Open channel
  tcpif.doCmdOpen("admin;secret;localhost\0");
 
  vscpMsg msg;
  msg.head = VSCP_PRIORITY_3;
  msg.obid = 0;
  msg.timestamp = 0;
  msg.vscp_class = 10;
  msg.vscp_type = 22;
  msg.pdata = new unsigned char[ 6 ];
  if ( NULL != msg.pdata ) {
 
    msg.sizeData = 6;
    msg.pdata[ 0 ] = 11;
    msg.pdata[ 1 ] = 22;
    msg.pdata[ 2 ] = 33;
    msg.pdata[ 3 ] = 44;
    msg.pdata[ 4 ] = 55;
    msg.pdata[ 5 ] = 66;
 
    // Send event
    tcpif.doCmdSend( &msg );
 
    delete [] msg.pdata;
  }
 
  msg.head = VSCP_PRIORITY_3;
  msg.obid = 0;
  msg.timestamp = 0;
  msg.vscp_class = 11;
  msg.vscp_type = 23;
 
  // Nill GUID
  memcpy( msg.GUID, 0, 16 );
 
  msg.pdata = new unsigned char[6];
  if ( NULL != msg.pdata ) {
 
    msg.sizeData = 6;
    msg.pdata[ 0 ] = 11;
    msg.pdata[ 1 ] = 22;
    msg.pdata[ 2 ] = 33;
    msg.pdata[ 3 ] = 44;
    msg.pdata[ 4 ] = 55;
    msg.pdata[ 5 ] = 66;
 
    // Send event
    tcpif.doCmdSend( &msg );
    delete [] msg.pdata;
    }
 
    vscpMsgEx msgex;
    msgex.head = VSCP_PRIORITY_3;
    msgex.obid = 0;
    msgex.timestamp = 0;
    msgex.vscp_class = 11;
    msgex.vscp_type = 23;
 
    // Nill GUID
    memcpy( msgex.GUID, 0, 16 );
 
    msgex.sizeData = 4;
    msgex.data[ 0 ] = 01;
    msgex.data[ 1 ] = 02;
    msgex.data[ 2 ] = 03;
    msgex.data[ 3 ] = 04;
 
    tcpif.doCmdSendEx( &msgex );
 
    // Receive event
 
    wxDateTime start,now;
    start.SetToCurrent();
    do {
      wxTimeSpan tt = wxDateTime::Now() - start;
 
      // Check for timeout
      if ( tt.GetSeconds() > 60 ) {
        break;
      }
 
      if ( tcpif.doCmdReceive( &msg ) ) {
        if ( NULL != msg.pdata ) delete msg.pdata;
    writeLog("Message received.");
    break;
      }
 
   } while ( true );
 
   // Close channel
   tcpif.doCmdClose();

Direct interface

This is the interface used by CanalWorks and the rest of the applications. There are several tools you can use that makes it simpler to start to use ths interface.

  • ActiveX controls. There is one for Level II and one for Level I (CAN). The difference is really how they look at the frames. The one for Level II understand class, type etc. The one for Level I think you are using CAN and you have to pack things yourself. They are both installed and registered during the install in windows.
  • dll's - There are dll's for both Level I and Level II also. testif dll in the canal VC project show how to use the Level I version and vscpdll in the vscp VC project shows how to use the Level II variant.
  • C plus plus classes. Also here there is one for Level I and one for Level II.
  canalshmem_level1_unix.cpp
  canalshmem_level1_unix.h
 
  canalshmem_level1_win32.cpp
  canalshmem_level1_win32.h
 
  canalshmem_level2_unix.cpp
  canalshmem_level2_unix.h
 
  canalshmem_level2_win32.cpp
  canalshmem_level2_win32.h

all located in the /src/canal/common folder of the source tree. For unix this is the only option at the moment. Check the cancmd on how to use them

Example on how to send Level I (CAN) frames using the CanalSharedMemLevel1 class.

#ifdef WIN32
 
#include "canalshmem_level1_win32.h"
 
#else
 
#include <unistd.h>
#include "canalshmem_level1_unix.h"
 
#endif
 
#include "../common/canal_macro.h"
 
CanalSharedMemLevel1 m_cmdif1;
 
if ( m_cmdif.doCmdOpen() ) {
 
   m_cmdif.doCmdNOOP(); // Just to no operation - does nothing
   m_cmdif.doCmdNOOP();
 
   canalMsg msg;
 
   // Standard message
   msg.flags = CANAL_IDFLAG_STANDARD;
   msg.obid = 0;
   msg.timestamp = 0;
   msg.id = 0x47;
   msg.sizeData = 4;
   msg.data[ 0 ] = 1;
   msg.data[ 1 ] = 2;
   msg.data[ 2 ] = 3;
   msg.data[ 3 ] = 4;
   m_cmdif.doCmdSend( &msg );
 
   msg.flags = CANAL_IDFLAG_EXTENDED;
   msg.obid = 0;
   msg.timestamp = 0;
   msg.id = 0x9047;
   msg.sizeData = 8;
   msg.data[ 0 ] = 11;
   msg.data[ 1 ] = 22;
   msg.data[ 2 ] = 33;
   msg.data[ 3 ] = 44;
   msg.data[ 4 ] = 55;
   msg.data[ 5 ] = 66;
   msg.data[ 6 ] = 77;
   msg.data[ 7 ] = 88;
 
   m_cmdif.doCmdSend( &msg );
 
   m_cmdif.doCmdNOOP();
   m_cmdif.doCmdNOOP();
 
   m_cmdif.doCmdClose();
}
else {
  printf("Error: Failed to open interface to canal daemon!\n");
}

Example on how to send Level II frames (Send VSCP message) using the CanalSharedMemLevel2 class.

#ifdef WIN32
 
#include "canalshmem_level2_win32.h"
 
#else
 
#include <unistd.h>
#include "canalshmem_level2_unix.h"
 
#endif
 
#include "../common/canal_macro.h"
 
 
    vscpMsg msg;
    CanalSharedMemLevel2 m_cmdif2;
 
    msg.vscp_class = 0;
    msg.vscp_type = 1;
 
    msg.GUID[ 0 ] = 0xff;
    msg.GUID[ 1 ] = 0xff;
    msg.GUID[ 2 ] = 0xff;
    msg.GUID[ 3 ] = 0xff;
    msg.GUID[ 4 ] = 0xff;
    msg.GUID[ 5 ] = 0xff;
    msg.GUID[ 6 ] = 0xff;
    msg.GUID[ 7 ] = 0xff;
    msg.GUID[ 8 ] = 0xff;
    msg.GUID[ 9 ] = 0xff;
    msg.GUID[ 10 ] = 0xff;
    msg.GUID[ 11 ] = 0xff;
    msg.GUID[ 12 ] = 0xff;
    msg.GUID[ 13 ] = 0xff;
    msg.GUID[ 14 ] = 0xff;
    msg.GUID[ 15 ] = 0x01;
 
    msg.sizeData = 2; // Nax 512-25 bytes
    msg.pdata[ 0 ] = 81;
    msg.pdata[ 1 ] = 82;
 
    if ( m_cmdif2.doCmdOpen() ) {
 
        if ( m_cmdif2.doCmdSend( &msg ) ) {
            printf("Success\n");
    }
        else {
            printf("Failure\n");
        }
 
        m_cmdif2.doCmdClose();
   }
   else {
        printf("Error: Failed to open Level II interface to canal daemon!\n");
   }

Example on how to receive Level I (CAN) frames using the CanalSharedMemLevel1 class.

#ifdef WIN32
 
#include "canalshmem_level1_win32.h"
#else
 
#include <unistd.h>
#include "canalshmem_level1_unix.h"
 
#endif
 
#include "../common/canal_macro.h"
 
CanalSharedMemLevel1 m_cmdif1;
 
if ( m_cmdif.doCmdOpen() ) {
 
  while ( ( -1 == cntToReceive ) || ( cntMessages < cntToReceive ) ) {
 
    if ( ( npackages = m_cmdif.doCmdDataAvailable() ) > 0 ) {
 
        for ( i = 0; i<npackages; i++ ) {
 
            if ( m_cmdif.doCmdReceive( &msg ) ) {
 
            // Get UNIX-style time and display as number and string.
            time( &ltime );
            strcpy( tempbuf, ctime( &ltime ) );
            tempbuf[ strlen( tempbuf ) - 1 ] = 0;    // Remove "/n"
 
            sprintf( buf, "%s - %08lX %08lX %08lX %02X - ",
                  tempbuf,
                  msg.timestamp,
                  msg.flags,
                  msg.id,
                  msg.sizeData );
 
            for ( int i=0; i < 8; i++ ) {
 
                if ( i < msg.sizeData ) {
                    sprintf( smallbuf, "%02X ", msg.data[ i ] );
                    strcat( buf, smallbuf );
                }
 
                }
 
                printf( "%s\n", buf );
 
                // Another package
                cntMessages++;
 
                }
 
        }
 
        }
        else {
        ::wxMilliSleep( 100 );
        }
 
    } // while
 
 
    // Close interface
    m_cmdif.doCmdClose();
}
else {
    printf("Error: Failed to open interface to canal daemon!\n");
}

Example on how to receive Level II frames using the CanalSharedMemLevel2 class.

#ifdef WIN32
 
#include "canalshmem_level2_win32.h""
#else
 
#include <unistd.h>
#include "canalshmem_level2_unix.h"
 
#endif
 
#include "../common/canal_macro.h"
 
int i,j;
CanalSharedMemLevel2 m_cmdif;
vscpMsg msg;
char buf[ 1024 ];
char smallbuf[ 256 ];
char tempbuf[ 32 ];
time_t ltime;
int cntMessages = 0;
int npackages;
 
if ( m_cmdif.doCmdOpen() ) {
 
    while ( ( -1 == cntToReceive ) || ( cntMessages < cntToReceive ) ) {
 
        if ( ( npackages = m_cmdif.doCmdDataAvailable() ) > 0 ) {
 
            for ( i = 0; i<npackages; i++ ) {
 
            if ( m_cmdif.doCmdReceive( &msg ) ) {
 
            // Get UNIX-style time and display as number and string.
            time( &ltime );
            strcpy( tempbuf, ctime( &ltime ) );
            tempbuf[ strlen( tempbuf ) - 1 ] = 0;            // Remove "/n"
 
            printf( "%s - \n\tTimestamp = %08lX Head = %02X Datasize = %04X \n",
                    tempbuf,
                msg.timestamp,
                msg.head,
                msg.sizeData );
 
            printf( "\tClass = %04X  Type = %04X \n",
                msg.vscp_class, msg.vscp_type );
 
            *buf = 0;
            for ( i=15; i>=0; i-- ) {
                sprintf( smallbuf, "%02X ", msg.GUID[ i ] );
            strcat( buf, smallbuf );
            }
            printf( "\tGUID = %s\n", buf );
 
            if ( NULL != msg.pdata ) {
 
                printf( "Data:\n" );
            for ( i=0; i < 32; i++ ) {
 
                *buf = 0;
                for ( j=0; j < 16; j++ ) {
 
                                if ( ( i * 16 + j ) < msg.sizeData ) {
                                    sprintf( smallbuf, "%02X ",
                                    msg.pdata[ ( i * 16 + j ) ] );
                                    strcat( buf, smallbuf );
                                }
 
                            }
                            printf( "\t%s\n", buf );
                            if ( ( i * 16 + j ) > msg.sizeData ) break;
 
                       }
                   }
                   else {
                       printf("\t No data.......\n");
                   }
 
                   printf("------------------------------------------------------------------------\n");
 
                   // Another package
           cntMessages++;
 
               }
 
           }
 
       }
       else {
           wxMilliSleep( 100 );
       }
 
    }
 
    // Close interface
    m_cmdif.doCmdClose();
}
else {
    printf("Error: Failed to open interface to canal daemon!\n");
}

Go back one level

howto/how_to_interface_the_daemon.txt · Last modified: 2011/01/19 13:14 by admin
Public Domain www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0