:!:This information is old or obsolete. See specification.
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:
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.
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.
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();
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.
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
#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"); }
#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"); }
#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( <ime ); strcpy( tempbuf, ctime( <ime ) ); 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"); }
#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( <ime ); strcpy( tempbuf, ctime( <ime ) ); 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"); }
Discussion