/*
* A low-level driver for EIB/Konnex bus access through USB
*
* (c) 2005 Heinz W. Werntges and Vladimir Vinarski
*
* $Id: knx_usb_driver.c,v 1.3 2005/10/29 22:43:47 werntges Exp $
*
* Revision history:
*
* $Log: knx_usb_driver.c,v $
* Revision 1.3 2005/10/29 22:43:47 werntges
* HWW: Sample code ( main() ) added
*
* Revision 1.2 2005/10/25 20:51:30 werntges
* HWW: knx_init() improved - Id's now checked if provided
*
* 2005-10-07 V 1.00 Derived from a precursor presented at KSC2005, Pisa
*
* License: Lesser GPL (see /http://www.gnu.org/licenses/ for details)
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#ifndef HID_MAX_USAGES
#define HID_MAX_USAGES 1024
#endif
#include <linux/hiddev.h>
int getUsageCode_Out0( int );
int match_fail( const char*, short );
/*
* Set ADD_MAIN to 1 in order to add a main() function with a little demo
*/
#define ADD_MAIN 0
#define READ_BUFFER_LENGTH 64
/* File-global */
unsigned long usageCode;
/*
* In: report - The report buffer, size should be at least 63 bytes
* bufsize - Buffer size, the max. number of bytes to be passed
* fd - The file descriptor as delivered by init()
* Out: report - Filled with the received bytes
*
* Returns: Number of bytes read, or a negative number on error
*/
int knx_receive( char* report, int bufsize, int fd )
{
struct hiddev_event readBuffer[READ_BUFFER_LENGTH];
int ret, n, i;
ret = (int) read( fd, readBuffer, sizeof(readBuffer) );
if( ret < 0 )
return ret;
n = ret / sizeof(readBuffer[0]);
for( i=0; i < n && i < bufsize; i++ )
report[i] = readBuffer[i].value;
return n;
}
/*
* In: report - The report buffer (always 64 bytes), including record_ID
* fd - The file descriptor as delivered by init()
* Out: -
*
* Returns: 0 if ok, or the error code of a failed ioctl() call
*/
int knx_send( const char report[64], int fd )
{
int rc = 0, uindex;
// send output report
struct hiddev_usage_ref uref;
struct hiddev_report_info rinfo;
// always send 63 bytes, assume 0x01 (report_id) is prepended
uref.report_id = *report++; // report_id byte: special treatment
uref.report_type = HID_REPORT_TYPE_OUTPUT;
uref.field_index = 0;
// uref.usage_code = 0xFFA10005;
uref.usage_code = usageCode;
for( uindex = 0; uindex < 63; uindex++ )
{
uref.usage_index = uindex;
uref.value = *report++;
if( (rc=ioctl( fd, HIDIOCSUSAGE, &uref )) != 0 )
{
return rc;
}
}
rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
rinfo.report_id = 0x01;
rinfo.num_fields = 1;
if( (rc=ioctl( fd, HIDIOCSREPORT, &rinfo )) != 0 )
{
return rc;
}
return 0;
}
/*
* In: device path - Typically, "/dev/usb/hiddev0"
* vendorId - 4 hex digits passed as a string, e.g. "2c58"
* productId - 4 hex digits passed as a string, see above
* versionId - 4 hex digits passed as a string, see above
* Out: -
*
* Returns: A valid file descriptor as returned by open(), or < 0 on error
*/
int knx_init( const char* device_path,
const char* vendorId,
const char* productId,
const char* versionId )
{
int fd = open ( device_path, O_RDWR );
if (fd < 0) return fd;
if (getUsageCode_Out0( fd ) < 0) return -8;
if (*vendorId != 0 || *productId != 0 || *versionId != 0) {
/*
* If vendorID, productId, or versionId provided:
* Check if device matches them!
*/
struct hiddev_devinfo device_info;
int rc = ioctl( fd, HIDIOCGDEVINFO, &device_info );
if (rc < 0) return -16;
if ((*vendorId != 0) && match_fail(vendorId, device_info.vendor))
return -4;
if ((*productId != 0) && match_fail(productId, device_info.product))
return -4;
if ((*versionId != 0) && match_fail(versionId, device_info.version))
return -4;
}
return fd;
}
/*
* In: fd - The file descriptor of the currently opened device
* Out: -
* Returns: 0 if ok, error code of close() if not
*/
int knx_exit( int fd )
{
return close( fd );
}
/*
* Internally used functions - don't export to Ruby!
*/
int getUsageCode_Out0( int fd )
{
struct hiddev_usage_ref uref;
int rc;
uref.report_type = HID_REPORT_TYPE_OUTPUT;
uref.report_id = 0x01;
uref.field_index = 0;
uref.usage_index = 0;
rc = ioctl( fd, HIDIOCGUCODE, &uref );
if (rc < 0) return rc;
usageCode = uref.usage_code;
return 0;
}
int match_fail( const char* id_string, short value )
{
int id;
sscanf( id_string, "%4x", &id );
return (id == value) ? 0 : 1;
}
#if ADD_MAIN
/*
* Some sample code to demonstrate usage
*
* Task: Determine supported EMI mode(s) of USB interface
*/
#include <stdlib.h>
#define RPT_SIZE 64
const unsigned char knxReportGetSupportedEMI_Types[] = {
0x01, // unsigned char reportId;
0x13, // unsigned char packetInfo;
0x09, // unsigned char dataLength;
0x00, // unsigned char protocolVersion;
0x08, // unsigned char headerLength;
0x00,0x01,// unsigned short bodyLength;
0x0F, // unsigned char protocolId;
0x01, // unsigned char emiId; // here: service Id
0x00, 0x00,// unsigned short manufactureCode;
0x01, // unsigned char emiMessageCode;
// pad to 64 byte
0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
};
int main(int argc, char **argv) {
int fd, rc;
char receive_buffer[RPT_SIZE];
fd = knx_init( "/dev/usb/hiddev0", "145c", "1330", "" );
if (fd < 0) {
printf( "knx_init() failed with err code %d\n", fd );
exit(-1);
}
rc = knx_send( knxReportGetSupportedEMI_Types, fd );
if (rc != 0) {
printf( "knx_send() failed with err code %d\n", rc );
exit(1);
}
/* Note:
*
* If the following call blocks despite correct outgoing report,
* consider to add a litte delay here (e.g. 50 ms).
*/
rc = knx_receive( receive_buffer, RPT_SIZE, fd );
if ( rc < 0 ) {
printf( "knx_receive() failed with err code %d\n", rc );
exit(2);
}
/* Expected result: 13 0B 00 08 00 03 0F 02 00 00 01 00 01 */
short unsigned res = receive_buffer[11] << 8 | receive_buffer[12];
printf ( "Result is %x\n", res);
if (res & 1) printf( "EMI1 supported\n" );
if (res & 2) printf( "EMI2 supported\n" );
if (res & 4) printf( "cEMI supported\n" );
printf( "Exiting...\n" );
knx_exit( fd );
return 0;
}
#endif
* A low-level driver for EIB/Konnex bus access through USB
*
* (c) 2005 Heinz W. Werntges and Vladimir Vinarski
*
* $Id: knx_usb_driver.c,v 1.3 2005/10/29 22:43:47 werntges Exp $
*
* Revision history:
*
* $Log: knx_usb_driver.c,v $
* Revision 1.3 2005/10/29 22:43:47 werntges
* HWW: Sample code ( main() ) added
*
* Revision 1.2 2005/10/25 20:51:30 werntges
* HWW: knx_init() improved - Id's now checked if provided
*
* 2005-10-07 V 1.00 Derived from a precursor presented at KSC2005, Pisa
*
* License: Lesser GPL (see /http://www.gnu.org/licenses/ for details)
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#ifndef HID_MAX_USAGES
#define HID_MAX_USAGES 1024
#endif
#include <linux/hiddev.h>
int getUsageCode_Out0( int );
int match_fail( const char*, short );
/*
* Set ADD_MAIN to 1 in order to add a main() function with a little demo
*/
#define ADD_MAIN 0
#define READ_BUFFER_LENGTH 64
/* File-global */
unsigned long usageCode;
/*
* In: report - The report buffer, size should be at least 63 bytes
* bufsize - Buffer size, the max. number of bytes to be passed
* fd - The file descriptor as delivered by init()
* Out: report - Filled with the received bytes
*
* Returns: Number of bytes read, or a negative number on error
*/
int knx_receive( char* report, int bufsize, int fd )
{
struct hiddev_event readBuffer[READ_BUFFER_LENGTH];
int ret, n, i;
ret = (int) read( fd, readBuffer, sizeof(readBuffer) );
if( ret < 0 )
return ret;
n = ret / sizeof(readBuffer[0]);
for( i=0; i < n && i < bufsize; i++ )
report[i] = readBuffer[i].value;
return n;
}
/*
* In: report - The report buffer (always 64 bytes), including record_ID
* fd - The file descriptor as delivered by init()
* Out: -
*
* Returns: 0 if ok, or the error code of a failed ioctl() call
*/
int knx_send( const char report[64], int fd )
{
int rc = 0, uindex;
// send output report
struct hiddev_usage_ref uref;
struct hiddev_report_info rinfo;
// always send 63 bytes, assume 0x01 (report_id) is prepended
uref.report_id = *report++; // report_id byte: special treatment
uref.report_type = HID_REPORT_TYPE_OUTPUT;
uref.field_index = 0;
// uref.usage_code = 0xFFA10005;
uref.usage_code = usageCode;
for( uindex = 0; uindex < 63; uindex++ )
{
uref.usage_index = uindex;
uref.value = *report++;
if( (rc=ioctl( fd, HIDIOCSUSAGE, &uref )) != 0 )
{
return rc;
}
}
rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
rinfo.report_id = 0x01;
rinfo.num_fields = 1;
if( (rc=ioctl( fd, HIDIOCSREPORT, &rinfo )) != 0 )
{
return rc;
}
return 0;
}
/*
* In: device path - Typically, "/dev/usb/hiddev0"
* vendorId - 4 hex digits passed as a string, e.g. "2c58"
* productId - 4 hex digits passed as a string, see above
* versionId - 4 hex digits passed as a string, see above
* Out: -
*
* Returns: A valid file descriptor as returned by open(), or < 0 on error
*/
int knx_init( const char* device_path,
const char* vendorId,
const char* productId,
const char* versionId )
{
int fd = open ( device_path, O_RDWR );
if (fd < 0) return fd;
if (getUsageCode_Out0( fd ) < 0) return -8;
if (*vendorId != 0 || *productId != 0 || *versionId != 0) {
/*
* If vendorID, productId, or versionId provided:
* Check if device matches them!
*/
struct hiddev_devinfo device_info;
int rc = ioctl( fd, HIDIOCGDEVINFO, &device_info );
if (rc < 0) return -16;
if ((*vendorId != 0) && match_fail(vendorId, device_info.vendor))
return -4;
if ((*productId != 0) && match_fail(productId, device_info.product))
return -4;
if ((*versionId != 0) && match_fail(versionId, device_info.version))
return -4;
}
return fd;
}
/*
* In: fd - The file descriptor of the currently opened device
* Out: -
* Returns: 0 if ok, error code of close() if not
*/
int knx_exit( int fd )
{
return close( fd );
}
/*
* Internally used functions - don't export to Ruby!
*/
int getUsageCode_Out0( int fd )
{
struct hiddev_usage_ref uref;
int rc;
uref.report_type = HID_REPORT_TYPE_OUTPUT;
uref.report_id = 0x01;
uref.field_index = 0;
uref.usage_index = 0;
rc = ioctl( fd, HIDIOCGUCODE, &uref );
if (rc < 0) return rc;
usageCode = uref.usage_code;
return 0;
}
int match_fail( const char* id_string, short value )
{
int id;
sscanf( id_string, "%4x", &id );
return (id == value) ? 0 : 1;
}
#if ADD_MAIN
/*
* Some sample code to demonstrate usage
*
* Task: Determine supported EMI mode(s) of USB interface
*/
#include <stdlib.h>
#define RPT_SIZE 64
const unsigned char knxReportGetSupportedEMI_Types[] = {
0x01, // unsigned char reportId;
0x13, // unsigned char packetInfo;
0x09, // unsigned char dataLength;
0x00, // unsigned char protocolVersion;
0x08, // unsigned char headerLength;
0x00,0x01,// unsigned short bodyLength;
0x0F, // unsigned char protocolId;
0x01, // unsigned char emiId; // here: service Id
0x00, 0x00,// unsigned short manufactureCode;
0x01, // unsigned char emiMessageCode;
// pad to 64 byte
0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
};
int main(int argc, char **argv) {
int fd, rc;
char receive_buffer[RPT_SIZE];
fd = knx_init( "/dev/usb/hiddev0", "145c", "1330", "" );
if (fd < 0) {
printf( "knx_init() failed with err code %d\n", fd );
exit(-1);
}
rc = knx_send( knxReportGetSupportedEMI_Types, fd );
if (rc != 0) {
printf( "knx_send() failed with err code %d\n", rc );
exit(1);
}
/* Note:
*
* If the following call blocks despite correct outgoing report,
* consider to add a litte delay here (e.g. 50 ms).
*/
rc = knx_receive( receive_buffer, RPT_SIZE, fd );
if ( rc < 0 ) {
printf( "knx_receive() failed with err code %d\n", rc );
exit(2);
}
/* Expected result: 13 0B 00 08 00 03 0F 02 00 00 01 00 01 */
short unsigned res = receive_buffer[11] << 8 | receive_buffer[12];
printf ( "Result is %x\n", res);
if (res & 1) printf( "EMI1 supported\n" );
if (res & 2) printf( "EMI2 supported\n" );
if (res & 4) printf( "cEMI supported\n" );
printf( "Exiting...\n" );
knx_exit( fd );
return 0;
}
#endif