Ingo Beckmann Ответов: 2

Доступ к термометру temper1f USB


Всем привет,

может ли кто-нибудь помочь мне или кто-нибудь решил такой проект.
Я купил два USB-термометра TEMPer1F и хочу получить к ним доступ, получить считанные с них значения температуры и записать их в базу данных SQL.
Я хотел бы сделать это, скорее всего, в AutoIT (предпочтительно) или другом языке сценариев, таком как VBS, JS или powershell.

Я нашел пример кода в C#, который взаимодействует с такого рода устройствами. Некоторые используют dll calle RDingUSB.dll некоторые напрямую используют Windows API/DLL, такие как USBlib и/или HID

Устройство представляет собой стандартное устройство HID.

Вот код, который я нашел в INET (это для LINUX, но мне он нужен для Windows 7+)
Единственное, что мне нужно, это получить список устройств =массив с одинаковыми VID и PID и считывать температуру с них в °C с точностью 0,1°
Первое я могу сделать сам.

Любая помощь приветствуется
Нашел пример кода :
#include <usb.h>
#include <stdio.h>
#include <time.h>

#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h> 
 
 
#define VERSION "0.0.1"
 
#define VENDOR_ID  0x0c45
#define PRODUCT_ID 0x7401
 
#define INTERFACE1 0x00
#define INTERFACE2 0x01
 
const static int reqIntLen=8;
const static int reqBulkLen=8;
const static int endpoint_Int_in=0x82; /* endpoint 0x81 address for IN */
const static int endpoint_Int_out=0x00; /* endpoint 1 address for OUT */
const static int endpoint_Bulk_in=0x82; /* endpoint 0x81 address for IN */
const static int endpoint_Bulk_out=0x00; /* endpoint 1 address for OUT */
const static int timeout=5000; /* timeout in ms */
 
const static char uTemperatura[] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 };
const static char uIni1[] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 };
const static char uIni2[] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 };
 /* Offset of temperature in read buffer; varies by product */
static size_t tempOffset;

static int bsalir=1;
static int debug=0;
static int seconds=5;
static int formato=0;
static int mrtg=0;

/* Even within the same VENDOR_ID / PRODUCT_ID, there are hardware variations
 * which we can detect by reading the USB product ID string. This determines
 * where the temperature offset is stored in the USB read buffer. */
const static struct product_hw {
    size_t      offset;
    const char *id_string;
} product_ids[] = {
    { 4, "TEMPer1F_V1.3" },
    { 2, 0 } /* default offset is 2 */
};

void bad(const char *why) {
        fprintf(stderr,"Fatal error> %s\n",why);
        exit(17);
}
 
 
usb_dev_handle *find_lvr_winusb();
 
void usb_detach(usb_dev_handle *lvr_winusb, int iInterface) {
        int ret;
 
	ret = usb_detach_kernel_driver_np(lvr_winusb, iInterface);
	if(ret) {
		if(errno == ENODATA) {
			if(debug) {
				printf("Device already detached\n");
			}
		} else {
			if(debug) {
				printf("Detach failed: %s[%d]\n",
				       strerror(errno), errno);
				printf("Continuing anyway\n");
			}
		}
	} else {
		if(debug) {
			printf("detach successful\n");
		}
	}
} 

usb_dev_handle* setup_libusb_access() {
     usb_dev_handle *lvr_winusb;

     if(debug) {
        usb_set_debug(255);
     } else {
        usb_set_debug(0);
     }
     usb_init();
     usb_find_busses();
     usb_find_devices();
             
 
     if(!(lvr_winusb = find_lvr_winusb())) {
                printf("Couldn't find the USB device, Exiting\n");
                return NULL;
        }
        
        
        usb_detach(lvr_winusb, INTERFACE1);
        

        usb_detach(lvr_winusb, INTERFACE2);
        
 
        if (usb_set_configuration(lvr_winusb, 0x01) < 0) {
                printf("Could not set configuration 1\n");
                return NULL;
        }
 

        // Microdia tiene 2 interfaces
        if (usb_claim_interface(lvr_winusb, INTERFACE1) < 0) {
                printf("Could not claim interface\n");
                return NULL;
        }
 
        if (usb_claim_interface(lvr_winusb, INTERFACE2) < 0) {
                printf("Could not claim interface\n");
                return NULL;
        }
 
        return lvr_winusb;
}
 

static void read_product_string(usb_dev_handle *handle, struct usb_device *dev)
{
    char prodIdStr[256];
    const struct product_hw *p;
    int strLen;

    memset(prodIdStr, 0, sizeof(prodIdStr));
    strLen = usb_get_string_simple(handle, dev->descriptor.iProduct, prodIdStr,
                                   sizeof(prodIdStr)-1);
    if (debug) {
        if (strLen < 0)
            puts("Couldn't read iProduct string");
        else
            printf("iProduct: %s\n", prodIdStr);
    }

    for (p = product_ids; p->id_string; ++p) {
        if (!strncmp(p->id_string, prodIdStr, sizeof(prodIdStr)))
            break;
    }
    tempOffset = p->offset;
}


usb_dev_handle *find_lvr_winusb() {
 
     struct usb_bus *bus;
        struct usb_device *dev;
 
        for (bus = usb_busses; bus; bus = bus->next) {
        for (dev = bus->devices; dev; dev = dev->next) {
                        if (dev->descriptor.idVendor == VENDOR_ID && 
                                dev->descriptor.idProduct == PRODUCT_ID ) {
                                usb_dev_handle *handle;
                                if(debug) {
                                  printf("lvr_winusb with Vendor Id: %x and Product Id: %x found.\n", VENDOR_ID, PRODUCT_ID);
                                }
 
                                if (!(handle = usb_open(dev))) {
                                        printf("Could not open USB device\n");
                                        return NULL;
                                }
                                read_product_string(handle, dev);
                                return handle;
                        }
                }
        }
        return NULL;
}
 
 
void ini_control_transfer(usb_dev_handle *dev) {
    int r,i;

    char question[] = { 0x01,0x01 };

    r = usb_control_msg(dev, 0x21, 0x09, 0x0201, 0x00, (char *) question, 2, timeout);
    if( r < 0 )
    {
          perror("USB control write"); bad("USB write failed"); 
    }


    if(debug) {
      for (i=0;i<reqIntLen; i++) printf("%02x ",question[i] & 0xFF);
      printf("\n");
    }
}
 
void control_transfer(usb_dev_handle *dev, const char *pquestion) {
    int r,i;

    char question[reqIntLen];
    
    memcpy(question, pquestion, sizeof question);

    r = usb_control_msg(dev, 0x21, 0x09, 0x0200, 0x01, (char *) question, reqIntLen, timeout);
    if( r < 0 )
    {
          perror("USB control write"); bad("USB write failed"); 
    }

    if(debug) {
        for (i=0;i<reqIntLen; i++) printf("%02x ",question[i]  & 0xFF);
        printf("\n");
    }
}

void interrupt_transfer(usb_dev_handle *dev) {
 
    int r,i;
    char answer[reqIntLen];
    char question[reqIntLen];
    for (i=0;i<reqIntLen; i++) question[i]=i;
    r = usb_interrupt_write(dev, endpoint_Int_out, question, reqIntLen, timeout);
    if( r < 0 )
    {
          perror("USB interrupt write"); bad("USB write failed"); 
    }
    r = usb_interrupt_read(dev, endpoint_Int_in, answer, reqIntLen, timeout);
    if( r != reqIntLen )
    {
          perror("USB interrupt read"); bad("USB read failed"); 
    }

    if(debug) {
       for (i=0;i<reqIntLen; i++) printf("%i, %i, \n",question[i],answer[i]);
    }
 
    usb_release_interface(dev, 0);
}

void interrupt_read(usb_dev_handle *dev) {
 
    int r,i;
    unsigned char answer[reqIntLen];
    bzero(answer, reqIntLen);
    
    r = usb_interrupt_read(dev, 0x82, (char*)answer, reqIntLen, timeout);
    if( r != reqIntLen )
    {
          perror("USB interrupt read"); bad("USB read failed"); 
    }

    if(debug) {
       for (i=0;i<reqIntLen; i++) printf("%02x ",answer[i]  & 0xFF);
    
       printf("\n");
    }
}

void interrupt_read_temperatura(usb_dev_handle *dev, float *tempC) {
 
    int r,i;
    unsigned char answer[reqIntLen];
    bzero(answer, reqIntLen);
    
    r = usb_interrupt_read(dev, 0x82, (char*)answer, reqIntLen, timeout);
    if( r != reqIntLen )
    {
          perror("USB interrupt read"); bad("USB read failed"); 
    }


    if(debug) {
      for (i=0;i<reqIntLen; i++) printf("%02x ",answer[i]  & 0xFF);
    
      printf("\n");
    }
    
    /* Temperature in C is a 16-bit signed fixed-point number, big-endian */
    *tempC = (float)(signed char)answer[tempOffset] +
             answer[tempOffset+1] / 256.0f;
}

void bulk_transfer(usb_dev_handle *dev) {
 
    int r,i;
    char answer[reqBulkLen];

    r = usb_bulk_write(dev, endpoint_Bulk_out, NULL, 0, timeout);
    if( r < 0 )
    {
          perror("USB bulk write"); bad("USB write failed"); 
    }
    r = usb_bulk_read(dev, endpoint_Bulk_in, answer, reqBulkLen, timeout);
    if( r != reqBulkLen )
    {
          perror("USB bulk read"); bad("USB read failed"); 
    }


    if(debug) {
      for (i=0;i<reqBulkLen; i++) printf("%02x ",answer[i]  & 0xFF);
    }
 
    usb_release_interface(dev, 0);
}
 

void ex_program(int sig) {
      bsalir=1;
 
      (void) signal(SIGINT, SIG_DFL);
}
 
int main( int argc, char **argv) {
 
     usb_dev_handle *lvr_winusb = NULL;
     float tempc;
     int c;
     struct tm *local;
     time_t t;

     while ((c = getopt (argc, argv, "mfcvhl::")) != -1)
     switch (c)
       {
       case 'v':
         debug = 1;
         break;
       case 'c':
         formato=1; //Celsius
         break;
       case 'f':
         formato=2; //Fahrenheit
         break;
       case 'm':
         mrtg=1;
         break;
       case 'l':
         if (optarg!=NULL){
           if (!sscanf(optarg,"%i",&seconds)==1) {
             fprintf (stderr, "Error: '%s' is not numeric.\n", optarg);
             exit(EXIT_FAILURE);
           } else {           
              bsalir = 0;
              break;
           }
         } else {
           bsalir = 0;
           seconds = 5;
           break;
         }
       case '?':
       case 'h':
         printf("pcsensor version %s\n",VERSION);
	 printf("      Aviable options:\n");
	 printf("          -h help\n");
	 printf("          -v verbose\n");
	 printf("          -l[n] loop every 'n' seconds, default value is 5s\n");
	 printf("          -c output only in Celsius\n");
	 printf("          -f output only in Fahrenheit\n");
	 printf("          -m output for mrtg integration\n");
  
	 exit(EXIT_FAILURE);
       default:
         if (isprint (optopt))
           fprintf (stderr, "Unknown option `-%c'.\n", optopt);
         else
           fprintf (stderr,
                    "Unknown option character `\\x%x'.\n",
                    optopt);
         exit(EXIT_FAILURE);
       }

     if (optind < argc) {
        fprintf(stderr, "Non-option ARGV-elements, try -h for help.\n");
        exit(EXIT_FAILURE);
     }
 
     if ((lvr_winusb = setup_libusb_access()) == NULL) {
         exit(EXIT_FAILURE);
     } 

     (void) signal(SIGINT, ex_program);

     ini_control_transfer(lvr_winusb);
      
     control_transfer(lvr_winusb, uTemperatura );
     interrupt_read(lvr_winusb);
 
     control_transfer(lvr_winusb, uIni1 );
     interrupt_read(lvr_winusb);
 
     control_transfer(lvr_winusb, uIni2 );
     interrupt_read(lvr_winusb);
     interrupt_read(lvr_winusb);


 
     do {
           control_transfer(lvr_winusb, uTemperatura );
           interrupt_read_temperatura(lvr_winusb, &tempc);

           t = time(NULL);
           local = localtime(&t);

           if (mrtg) {
              if (formato==2) {
                  printf("%.2f\n", (9.0 / 5.0 * tempc + 32.0));
                  printf("%.2f\n", (9.0 / 5.0 * tempc + 32.0));
              } else {
                  printf("%.2f\n", tempc);
                  printf("%.2f\n", tempc);
              }
              
              printf("%02d:%02d\n", 
                          local->tm_hour,
                          local->tm_min);

              printf("pcsensor\n");
           } else {
              printf("%04d/%02d/%02d %02d:%02d:%02d ", 
                          local->tm_year +1900, 
                          local->tm_mon + 1, 
                          local->tm_mday,
                          local->tm_hour,
                          local->tm_min,
                          local->tm_sec);

              if (formato==2) {
                  printf("Temperature %.2fF\n", (9.0 / 5.0 * tempc + 32.0));
              } else if (formato==1) {
                  printf("Temperature %.2fC\n", tempc);
              } else {
                  printf("Temperature %.2fF %.2fC\n", (9.0 / 5.0 * tempc + 32.0), tempc);
              }
              fflush(stdout);
           }
           
           if (!bsalir)
              sleep(seconds);
     } while (!bsalir);
                                       
     usb_release_interface(lvr_winusb, INTERFACE1);
     usb_release_interface(lvr_winusb, INTERFACE2);
     
     usb_close(lvr_winusb); 
      
     return 0; 
}


Что я уже пробовал:

Я попытался проанализировать код C#, но так как у меня нет никаких знаний или опыта в C#
Я не могу получить ничего из кода, который я могу использовать в качестве основы для реализации его на моих известных языках.

phil.o

Это не C#; это С++С.

#realJSOP

Верд!

phil.o

Что это значит?

#realJSOP

На уличном жаргоне это означает "вы правы, сэр". Я просто пытался поднять вопрос-Ну, вы понимаете - сделать его законным для комплекта.

Jochen Arndt

Это C, а не C++.

phil.o

Да, спасибо, что поправил.

Ingo Beckmann

Извиняюсь.
Как вы все видите, я ничего не знаю о С.... Независимость от рода с

Ingo Beckmann

Любой намек будет приветствоваться

2 Ответов

Рейтинг:
2

Jochen Arndt

Доступ к таким устройствам требует связи с драйвером устройства. Это может быть невозможно с помощью скриптовых языков, но я не могу сказать наверняка. Это возможно с языками программирования в том числе .Сетевые языки, такие как C# и VB.Net, а также с помощью PowerShell. Я не знаю о VBS (который я все равно предлагаю удалить из вашего списка) и AutoIt.

Поскольку каждый язык (или группа для .Net) имеет свой собственный метод(ы) для доступа к таким устройствам, вы должны сначала выбрать язык. Выберите язык, который вы уже знаете. Затем найдите поддерживаемые методы для этого конкретного языка. Игнорируйте любые примеры для другого языка, потому что они вам не помогут.

Пример кода C из вашего вопроса использует (низкий уровень) libusb библиотека на Linux. Существует версия Windows для этой библиотеки, так что код также может быть использован с C/C++ в Windows. Есть и такие .Библиотеки сетевых классов, предоставляющие сходные - но не идентичные - функции.

Самое простое решение - это когда существует драйвер виртуального COM-порта для вашего устройства. Затем вы можете общаться с помощью функций последовательного интерфейса, которые должны поддерживаться всеми языками, включая языки сценариев.

Большинство производителей таких устройств предоставляют также SDK, включающий библиотеку, DLL и заголовочные файлы для C/C++. Информация из них может быть использована для доступа к библиотеке DLL из .Сеть с использованием PInvoke.

[РЕДАКТИРОВАТЬ]
Быстрое исследование показало, что AutoIt поддерживает вызовы DLL: DllCall[^]

Имена функций и соответствующие типы возвращаемых значений и типы параметров должны быть задокументированы поставщиком библиотеки DLL или могут быть найдены в заголовочном файле языка C.

Я предлагаю использовать DLL, предоставленную производителем устройства, потому что использование этого приведет к меньшему количеству кода, чем низкий уровень libusb из кода на языке Си, который вы нашли.
[/РЕДАКТИРОВАТЬ]


Ingo Beckmann

Там нет никаких конвертеров или драйверов, обеспечивающих COM-порты
это настоящее скрытое устройство. У меня есть dll, выполняющая эту связь с USB-устройством, называемым RDingUSB.dll-да. Мне было бы полезно узнать, как получить доступ к его функциям и как работать с более чем 1 устройством с одинаковыми VID и PID
Тогда я могу реализовать это в AutoIT например

Jochen Arndt

Виртуальный COM-порт водитель использует библиотеку DLL устройства (DRingUsb.dll) для имитации последовательного порта в программном обеспечении. Я упомянул его только на тот случай, если он существует.

Для доступа к нескольким устройствам с одинаковыми PID и VID требуется, чтобы они имели серийные номера. Если нет, то Windows назначит GUID в соответствии с USB-портом, что затруднит идентификацию конкретного устройства.

Сначала вы должны проверить, поддерживает ли AutoIt вызов функций из импортированной библиотеки DLL. Если это не поддерживается, вы не можете использовать AutoIt. Для других языков это зависит от языка, как уже объяснялось. Общего решения / метода не существует.

Ingo Beckmann

Я только хотел использовать найденный код, чтобы узнать, как вызвать функции и получить значение, считанное в моих известных языках

Jochen Arndt

Для использования кода вам нужен Windows-порт библиотеки libusb (которая содержит собственную DLL) и доступ к нему, как к любой другой DLL. Но скриптовые языки обычно не поддерживают прямой доступ к DLL (кроме PowerShell) и .Net требует использования PInvoke.

Ingo Beckmann

В RDingUSB.dll используется с помощью программного обеспечения идет на компакт-диске с устройством.

Jochen Arndt

Вы должны сделать то же самое, что и для libusb:
Откройте библиотеку DLL.

Эти функции перечислены в (надеюсь) предоставленном заголовочном файле C SDK. Но использование этой библиотеки DLL должно быть проще, чем libusb (меньше функций для вызова).

Ingo Beckmann

AutoIT может сделать это
Я могу вызвать библиотеку DLL и взаимодействовать с ней
Я извлек список функций из RDingUSB.dll с помощью средства просмотра экспорта DLL
Единственное, чего сейчас не хватает, - это как получить к нему доступ с помощью вызовов функций.
Параметры, длина и т. д.
Я предоставлю список функций здесь в ближайшем будущем

Jochen Arndt

Смотрите мой обновленный ответ, который я опубликовал вскоре после вашего комментария.
В составе SDK должна быть какая-то документация. Типы параметров могут быть получены из файла заголовка C, но тогда вам все равно нужно знать, что делает функция и как ее вызвать (какие значения параметров ожидаются).

Рейтинг:
1

OriginalGriff

Не пытайтесь конвертировать C - код в C#: то, что вы получите, не будет работать очень хорошо - если вообще будет работать-и будет нелегко поддерживать.

Вместо этого посмотрите на код, который у вас есть, и точно определите, что он делает. Затем используйте это как спецификацию для кода C#, который вам нужен. Вам понадобится Последовательный порт[^] для связи с устройством.

- Я? Я бы начал с веб-сайта производителей и посмотрел, есть ли у них какой-нибудь пример кода на C#, а затем работал бы оттуда...