#include "heha_print.h" // heha::
#include <dirent.h> // opendir()
#include <unistd.h> // read()
#include <fcntl.h> // open()
#include <string.h> // memcmp()
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
typedef unsigned char byte;
// USB-Gerät per Filterfunktion finden.
// Die Filterfunktion bekommt die 3 Deskriptoren in einem Stück.
// Sowie das Handle um ggf. String-Deskriptoren zu holen.
int findUsbDevice(bool(*cb)(void*,int,byte*,int),void*cbd) {
static const char buslist[]="/dev/bus/usb";
DIR*dBus = opendir(buslist);
if (!dBus) return -1;
while (dirent*busent=readdir(dBus)) {
char dname[32];
heha::snprint(dname,sizeof dname,"%s/%s",buslist,busent->d_name);
DIR*dDev = opendir(dname); // dname muss ein Verzeichnis sein
if (!dDev) continue;
while (dirent*devent=readdir(dDev)) {
char fname[32];
heha::snprint(fname,sizeof fname,"%s/%s",dname,devent->d_name);
int h = open(fname,O_RDWR); // fname muss ein lesbares Zeichengerät sein
if (h<0) h = open(fname,O_RDONLY);
if (h<0) continue;
byte desc[256];
int l = read(h,desc,sizeof desc);
if (l>=18+9 && cb(cbd,h,desc,l)) {
closedir(dDev);
closedir(dBus);
return h; // offenes Handle liefern
}else{
close(h);
}
}
closedir(dDev);
}
closedir(dBus);
return -1;
}
struct I2c{
virtual bool queryLong(const void*,int,void*,int,const char* =0) const =0;
virtual ~I2c() {};
};
struct UsbI2c: public I2c{
int h;
int n;
char iface;
operator bool() const {return h>=0;}
static bool FindCb(void*cbd,int h,byte*desc,int dlen) {
return ((UsbI2c*)cbd)->Finder(h,desc,dlen);
}
bool Finder(int h,byte*desc,int dlen) {
#define W(x) (x)&0xFF,(x)>>8
static const byte matchdesc[36]={
18, 1, W(0x0200), 0, 0, 0, 64, // device desc
W(0x16C0), W(0x27D8), W(0x0200),
1,2,3,1,
9,2,W(18),1,1,0,0x80,10, // config desc
9,4,0,0,0,0xFF,0,0,0}; // iface desc
#undef W
/*
00000000 12 01 00 02 00 00 00 40 c0 16 d8 27 00 02 01 02 |.......@...'....|
00000010 03 01 09 02 12 00 01 01 00 80 0a 09 04 00 00 00 |................|
00000020 ff 00 00 00 |....|
*/
// Hier: Das Gerät ist per VID+PID bekannt, und deshalb müssen die Deskriptoren nicht weiter geparst werden
return dlen==sizeof matchdesc
&& !memcmp(desc,matchdesc,sizeof matchdesc)
&& !--n;
}
UsbI2c():h(-1),n(1),iface(1) {
h = findUsbDevice(FindCb,this);
if (h>=0) {
if (ioctl(h,USBDEVFS_CLAIMINTERFACE,iface)<0)
heha::print("ClaimInterface(%u): Fehler %u: %s\n",iface,errno,strerror(errno));
}
}
bool queryLong(const void*s,int sl,void*r,int rl,const char* =0) const override{
if (h<0) return false;
const unsigned to=100;
if (sl<=2) {
usbdevfs_ctrltransfer xfer ={
0b11000000, // bmRequestType (read/vendor/device)
0xA0, // bRequest
__u16(0x5D|sl<<12), //wValue = I²C-Adresse (7 oder 10 Bit) + Subadresslänge
*(__u16*)(s), //wIndex = die ersten beiden Bytes
__u16(rl), //wLength
to, //timeout
r}; //data
if (ioctl(h,USBDEVFS_CONTROL,xfer)<0) {
heha::print("queryLong(wl<=2): %u = %s\n",errno,strerror(errno));
return false;
}
return true;
}
if (!rl) {
usbdevfs_ctrltransfer xfer ={
0b01000000, // bmRequestType (write/vendor/device)
0xA0, // bRequest
0x5D, // wValue = I²C-Adresse (7 oder 10 Bit)
0, // wIndex
__u16(sl), // wLength
to, // timeout
const_cast<void*>(s)}; // data
if (ioctl(h,USBDEVFS_CONTROL,xfer)<0) {
heha::print("queryLong(rl=0): %u = %s\n",errno,strerror(errno));
return false;
}
return true;
}
return false; // sollte hier nie auftreten!
}
unsigned getLastError() const{
if (h<0) return 1021;
byte b;
usbdevfs_ctrltransfer xfer ={
0b11000000, // bmRequestType (read/vendor/device)
0xA1, // bRequest
0, // wValue (ungenutzt)
0, // wIndex (ungenutzt)
1, // wLength (1 Byte)
100, // timeout
&b}; // data
if (ioctl(h,USBDEVFS_CONTROL,xfer)<0) {
heha::print("getLastError: %u = %s\n",errno,strerror(errno));
return 1000+errno;
}
return b;
}
~UsbI2c() override{
if (h>=0) {
ioctl(h,USBDEVFS_RELEASEINTERFACE,iface);
close(h);
}
}
};
int main() {
UsbI2c test;
if (test) {
heha::print("Gefunden!\n");
byte buf[6];
if (test.queryLong("\x01\x60",2,buf,sizeof buf)) // Uhrzeit holen
for (byte b:buf) heha::print("%02X ",b);
else heha::print("Keine Antwort, Fehler %u!\n",test.getLastError());
}else heha::print("Nicht gefunden!\n");
}
Detected encoding: UTF-8 | 0
|