Compare commits

..

4 Commits

Author SHA1 Message Date
e9c521c0e4 updated dependencies 2024-10-16 00:44:41 +02:00
ed51155640 updated sensor 2023-12-01 14:00:21 +01:00
9d010120d5 added sensor 2023-11-08 17:11:32 +01:00
5d15838757 updated pcsensor.c with new sensor 2023-03-07 18:31:50 +01:00
8 changed files with 268 additions and 608 deletions

201
Cargo.lock generated
View File

@ -1,21 +1,126 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "cc"
version = "1.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
dependencies = [
"jobserver",
"libc",
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.169" version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]] [[package]]
name = "libusb-sys" name = "memchr"
version = "0.2.3" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c53b6582563d64ad3e692f54ef95239c3ea8069e82c9eb70ca948869a7ad767" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [ dependencies = [
"libc", "memchr",
"pkg-config", "minimal-lexical",
] ]
[[package]] [[package]]
@ -24,10 +129,88 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "proc-macro2"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "sensor" name = "sensor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bindgen",
"cc",
"libc", "libc",
"libusb-sys", "pkg-config",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"

View File

@ -2,13 +2,12 @@
name = "sensor" name = "sensor"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
#build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
libc = "0.2" libc = "0.2"
libusb-sys = "0.2"
#[build-dependencies] [build-dependencies]
#cc = { version = "1.0", features = ["parallel"] } cc = { version = "1.1", features = ["parallel"] }
#bindgen = { version = "0.59", default-features = false} bindgen = { version = "0.70", default-features = false }
#pkg-config = "0.3" pkg-config = "0.3"

View File

@ -1,61 +0,0 @@
# sensor
## Summary
PCSensor temper with Rust and C bindings
## Dependencies
* libclang-dev
* libusb-1.0-0-dev
## Howto
### Dev Run
```
cargo r
```
### Build
```bash
cargo b -r
```
## TODO
## License
```text
Copyright (c) 2022, 2023 PaulBSD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of this project.
```

View File

@ -1,8 +1,8 @@
extern crate bindgen; extern crate bindgen;
use cc; use cc;
use std::path::PathBuf;
use std::env; use std::env;
use std::path::PathBuf;
fn main() { fn main() {
println!("cargo:rerun-if-changed=src/pcsensor.c"); println!("cargo:rerun-if-changed=src/pcsensor.c");
@ -14,7 +14,7 @@ fn main() {
fn bind() { fn bind() {
let bindings = bindgen::Builder::default() let bindings = bindgen::Builder::default()
.header("/usr/include/libusb-1.0/libusb.h") .header("/usr/include/libusb-1.0/libusb.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks)) .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate() .generate()
.expect("Unable to generate bindings"); .expect("Unable to generate bindings");
@ -26,10 +26,10 @@ fn bind() {
fn compile_pcsensor() { fn compile_pcsensor() {
cc::Build::new() cc::Build::new()
.file("src/pcsensor.c") .file("src/pcsensor.c")
.shared_flag(true) .shared_flag(true)
.static_flag(true) .static_flag(true)
.compile("pcsensor"); .compile("pcsensor");
} }
fn link() { fn link() {

View File

@ -2,4 +2,4 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
//include!(concat!(env!("OUT_DIR"), "/bindings.rs")); include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@ -1,14 +1,13 @@
pub mod temp; use libc;
use temp::*; #[link(name = "pcsensor")]
#[link(name = "usb-1.0")]
//#[link(name = "pcsensor")] extern "C" {
//#[link(name = "usb-1.0")] fn get_temp_c() -> libc::c_float;
//extern "C" { }
// fn get_temp_c() -> libc::c_float;
//}
fn main() { fn main() {
let temperature = get_temp_r(); unsafe {
println!("{}", temperature); println!("{}", get_temp_c());
}
} }

View File

@ -22,6 +22,7 @@ typedef struct {
const int has_sensor; // number of temperature sensor const int has_sensor; // number of temperature sensor
const int has_humid; // flag for humidity sensor const int has_humid; // flag for humidity sensor
void (*decode_func)(); void (*decode_func)();
float divisor;
} temper_type_t; } temper_type_t;
typedef struct { typedef struct {
@ -29,15 +30,24 @@ typedef struct {
temper_type_t *type; temper_type_t *type;
} temper_device_t; } temper_device_t;
void decode_answer_fm75(); void decode_answer();
void decode_answer_sht1x();
#define TEMPER_TYPES 4
const char GetFirmware[8] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 };
const char GetTemperature[8] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 };
//#define Temperature { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 }
//const char uTemperature1[8] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 };
//const char uTemperature2[8] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 };
//const char uTemperature3[8] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 };
#define TEMPER_TYPES 3
temper_type_t tempers[TEMPER_TYPES] = { temper_type_t tempers[TEMPER_TYPES] = {
{0x0c45, 0x7401, "TEMPer2", 1, 2, 0, decode_answer_fm75}, // TEMPer2* eg. TEMPer2V1.3 {0x1a86, 0xe025, "TEMPerGold", 1, 1, 0, decode_answer, 100.0},
{0x0c45, 0x7401, "TEMPer1", 0, 1, 0, decode_answer_fm75}, // other 0c45:7401 eg. TEMPerV1.4 {0x0c45, 0x7401, "TEMPer2", 1, 2, 0, decode_answer, 256.0},
{0x0c45, 0x7402, "TEMPerHUM", 0, 1, 1, decode_answer_sht1x}, {0x0c45, 0x7401, "TEMPer1", 0, 1, 0, decode_answer, 256.0},
//{0x0c45, 0x7402, "TEMPerHUM", 0, 1, 1, decode_answer_sht1x, 100.0},
}; };
/* memo: TEMPer2 cannot be distinguished with VID:PID, /* memo: TEMPer2 cannot be distinguished with VID:PID,
@ -51,12 +61,9 @@ temper_type_t tempers[TEMPER_TYPES] = {
#define INTERFACE2 0x01 #define INTERFACE2 0x01
const int reqIntLen = 8; const int reqIntLen = 8;
const int endpoint_Int_in = 0x82; /* endpoint 0x81 address for IN */ const int endpoint_Int_out = 0x02;
const int timeout = 5000; /* timeout in ms */ const int endpoint_Int_in = 0x82;
const int timeout = 300; /* timeout in ms */
const char uTemperature[] = {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 };
static int bsalir = 1; static int bsalir = 1;
static int debug = 0; static int debug = 0;
@ -156,7 +163,6 @@ int find_lvr_winusb(temper_device_t *devices) {
} }
int setup_libusb_access(temper_device_t *devices) { int setup_libusb_access(temper_device_t *devices) {
int i;
int log_level = 0; int log_level = 0;
int numdev; int numdev;
@ -176,10 +182,10 @@ int setup_libusb_access(temper_device_t *devices) {
return -1; return -1;
} }
for (i = 0; i < numdev; i++) { for (int i = 0; i < numdev; i++) {
usb_detach(devices[i].handle, INTERFACE1); usb_detach(devices[i].handle, INTERFACE1);
usb_detach(devices[i].handle, INTERFACE2); usb_detach(devices[i].handle, INTERFACE2);
libusb_reset_device(devices[i].handle); //libusb_reset_device(devices[i].handle);
if (libusb_set_configuration(devices[i].handle, 0x01) < 0) { if (libusb_set_configuration(devices[i].handle, 0x01) < 0) {
fprintf(stderr, "Could not set configuration 1\n"); fprintf(stderr, "Could not set configuration 1\n");
@ -201,25 +207,6 @@ int setup_libusb_access(temper_device_t *devices) {
return numdev; return numdev;
} }
void ini_control_transfer(libusb_device_handle *dev) {
int r, i;
char question[reqIntLen];
question[0] = 0x01;
question[1] = 0x01;
r = libusb_control_transfer(dev, 0x21, 0x09, 0x0201, 0x00, (unsigned char *)question, 2, timeout);
if (r < 0) {
perror("USB control write");
bad("USB write failed");
}
if (debug) {
for (i = 0; i < reqIntLen; i++) fprintf(stderr, "%02x ", question[i] & 0xFF);
fprintf(stderr, "\n");
}
}
void control_transfer(libusb_device_handle *dev, const char *pquestion) { void control_transfer(libusb_device_handle *dev, const char *pquestion) {
int r, i; int r, i;
@ -230,7 +217,7 @@ void control_transfer(libusb_device_handle *dev, const char *pquestion) {
r = libusb_control_transfer(dev, 0x21, 0x09, 0x0200, 0x01, (unsigned char *)question, reqIntLen, timeout); r = libusb_control_transfer(dev, 0x21, 0x09, 0x0200, 0x01, (unsigned char *)question, reqIntLen, timeout);
if (r < 0) { if (r < 0) {
perror("USB control write"); perror("USB control write");
bad("USB write failed"); return;
} }
if (debug) { if (debug) {
@ -240,15 +227,25 @@ void control_transfer(libusb_device_handle *dev, const char *pquestion) {
} }
} }
void interrupt_read(libusb_device_handle *dev, unsigned char *answer) { void interrupt_read(libusb_device_handle *dev, unsigned char *answer, const char *pquestion, const char *product_name) {
int r, s, i; int r, s, i;
char question[reqIntLen];
memset(answer, 0, reqIntLen); memset(answer, 0, reqIntLen);
memcpy(question, pquestion, sizeof question);
s = libusb_interrupt_transfer(dev, endpoint_Int_in, answer, reqIntLen, &r, timeout); s = libusb_interrupt_transfer(dev, endpoint_Int_in, answer, reqIntLen, &r, timeout);
if (r != reqIntLen) {
fprintf(stderr, "USB read failed: %d\n", s); if (strcmp(product_name, "TEMPerGold") == 0) {
libusb_interrupt_transfer(dev, endpoint_Int_out, (unsigned char *)question, reqIntLen, &r, timeout);
s = libusb_interrupt_transfer(dev, endpoint_Int_in, answer, reqIntLen, &r, timeout);
}
if (s != 0) {
fprintf(stderr, "USB read failed: %s\n", libusb_error_name(s));
perror("USB interrupt read"); perror("USB interrupt read");
bad("USB read failed"); exit(1);
return;
} }
if (debug) { if (debug) {
@ -260,12 +257,13 @@ void interrupt_read(libusb_device_handle *dev, unsigned char *answer) {
} }
void cleanup_usb_devices(temper_device_t *devices, int numdev) { void cleanup_usb_devices(temper_device_t *devices, int numdev) {
int i; for (int i = 0; i < numdev; i++) {
for (i = 0; i < numdev; i++) {
libusb_release_interface(devices[i].handle, INTERFACE1); libusb_release_interface(devices[i].handle, INTERFACE1);
libusb_release_interface(devices[i].handle, INTERFACE2); libusb_release_interface(devices[i].handle, INTERFACE2);
libusb_attach_kernel_driver(devices[i].handle, INTERFACE1);
libusb_attach_kernel_driver(devices[i].handle, INTERFACE2);
libusb_close(devices[i].handle); libusb_close(devices[i].handle);
} }
@ -278,24 +276,22 @@ void ex_program() {
(void)signal(SIGINT, SIG_DFL); (void)signal(SIGINT, SIG_DFL);
} }
/* decode funcs */ void decode_answer(unsigned char *answer, float *divisor, float *tempd, float *calibration) {
/* Thanks to https://github.com/edorfaus/TEMPered */
void decode_answer_fm75(unsigned char *answer, float *tempd, float *calibration) {
int buf; int buf;
// temp C internal // temp C internal
buf = ((signed char)answer[2] << 8) + (answer[3] & 0xFF); buf = ((signed char)answer[2] << 8) + (answer[3] & 0xFF);
tempd[0] = buf * (125.0 / 32000.0); tempd[0] = buf / *divisor;
tempd[0] = tempd[0] * calibration[0] + calibration[1]; tempd[0] = tempd[0] * calibration[0] + calibration[1];
// temp C external // temp C external
buf = ((signed char)answer[4] << 8) + (answer[5] & 0xFF); buf = ((signed char)answer[4] << 8) + (answer[5] & 0xFF);
tempd[1] = buf * (125.0 / 32000.0); tempd[1] = buf / *divisor;
tempd[1] = tempd[1] * calibration[0] + calibration[1]; tempd[1] = tempd[1] * calibration[0] + calibration[1];
} }
void decode_answer_sht1x(unsigned char *answer, float *tempd, float *calibration) { /*
void decode_answer_sht1x(unsigned char *answer, float *divisor, float *tempd, float *calibration) {
int buf; int buf;
// temp C // temp C
@ -307,13 +303,17 @@ void decode_answer_sht1x(unsigned char *answer, float *tempd, float *calibration
buf = ((signed char)answer[4] << 8) + (answer[5] & 0xFF); buf = ((signed char)answer[4] << 8) + (answer[5] & 0xFF);
tempd[1] = -2.0468 + 0.0367 * buf - 1.5955e-6 * buf * buf; tempd[1] = -2.0468 + 0.0367 * buf - 1.5955e-6 * buf * buf;
tempd[1] = (tempd[0] - 25) * (0.01 + 0.00008 * buf) + tempd[1]; tempd[1] = (tempd[0] - 25) * (0.01 + 0.00008 * buf) + tempd[1];
if (tempd[1] < 0) tempd[1] = 0; if (tempd[1] < 0)
if (tempd[1] > 99) tempd[1] = 100; tempd[1] = 0;
if (tempd[1] > 99)
tempd[1] = 100;
} }
*/
float get_temp_c() { float get_temp_c() {
temper_device_t *devices; temper_device_t *devices;
int numdev, i; int numdev;
int i = 0;
unsigned char *answer; unsigned char *answer;
float tempd[2]; float tempd[2];
float calibration[2] = {1, 0}; float calibration[2] = {1, 0};
@ -327,10 +327,9 @@ float get_temp_c() {
answer = calloc(reqIntLen, sizeof(unsigned char)); answer = calloc(reqIntLen, sizeof(unsigned char));
i = 0; control_transfer(devices[i].handle, GetTemperature);
control_transfer(devices[i].handle, uTemperature); interrupt_read(devices[i].handle, answer, GetTemperature, devices[i].type->product_name);
interrupt_read(devices[i].handle, answer); devices[i].type->decode_func(answer, &devices[i].type->divisor, tempd, calibration);
devices[i].type->decode_func(answer, tempd, calibration);
cleanup_usb_devices(devices, numdev); cleanup_usb_devices(devices, numdev);

View File

@ -1,459 +0,0 @@
use std::ffi::CStr;
use std::ptr::{null_mut, slice_from_raw_parts};
use libusb_sys::*;
const MAX_DEV: usize = 8;
const INTERFACE1: i32 = 0x00;
const INTERFACE2: i32 = 0x01;
const REQINTLEN: usize = 8;
const ENDPOINT_INT_IN: u8 = 0x82;
const TIMEOUT: u32 = 5000;
const UTEMPERATURE: &[u8; 8] = &[0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00];
static mut DEBUG: bool = false;
const TEMPER_TYPES: usize = 3;
const TEMPERS: [TemperType; TEMPER_TYPES] = [
TemperType {
vendor_id: 0x0c45,
product_id: 0x7401,
product_name: "TEMPer2",
check_product_name: true,
has_sensor: true,
has_humid: false,
}, // TEMPer2* eg. TEMPer2V1.3
TemperType {
vendor_id: 0x0c45,
product_id: 0x7401,
//product_name: "TEMPer1",
product_name: "TEMPerV1.4",
check_product_name: false,
has_sensor: true,
has_humid: false,
}, // other 0c45:7401 eg. TEMPerV1.4
TemperType {
vendor_id: 0x0c45,
product_id: 0x7402,
product_name: "TEMPerHUM",
check_product_name: false,
has_sensor: true,
has_humid: true,
}, //decode_answer_sht1x},
];
#[derive(Clone, Debug)]
pub struct TemperType {
pub vendor_id: u16,
pub product_id: u16,
pub product_name: &'static str,
pub check_product_name: bool,
pub has_sensor: bool,
pub has_humid: bool,
}
impl TemperType {
pub fn decode(&self, answer: &[u8; 100], tempd: &mut [f32; 2], calibration: &[f32; 2]) {
match self.product_name {
"TEMPer2" => self.decode_answer_fm75(answer, tempd, calibration),
"TEMPerV1.4" => self.decode_answer_fm75(answer, tempd, calibration),
_ => self.decode_answer_fm75(answer, tempd, calibration),
}
}
pub fn decode_answer_fm75(
&self,
answer: &[u8; 100],
tempd: &mut [f32; 2],
calibration: &[f32; 2],
) {
let mut buf: u16;
buf = ((answer[2] as u16) << 8) + ((answer[3] as u16) & 0xFF);
tempd[0] = buf as f32 * (125.0 / 32000.0);
tempd[0] = tempd[0] * calibration[0] + calibration[1];
buf = ((answer[4] as u16) << 8) as u16 + ((answer[5] as u16) & 0xFF) as u16;
tempd[1] = buf as f32 * (125.0 / 32000.0);
tempd[1] = tempd[1] * calibration[0] + calibration[1];
}
}
impl Default for TemperType {
fn default() -> Self {
Self {
vendor_id: 0,
product_id: 0,
product_name: "",
check_product_name: true,
has_sensor: false,
has_humid: false,
}
}
}
impl Copy for TemperType {}
impl std::fmt::Display for TemperType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"vendor_id: {}, product_id: {}, product_name: {}",
self.vendor_id, self.product_id, self.product_name
)
}
}
#[derive(Clone)]
pub struct TemperDevice {
handle: *mut *mut libusb_device_handle,
t: TemperType,
}
impl Copy for TemperDevice {}
impl Default for TemperDevice {
fn default() -> Self {
Self {
handle: null_mut(),
t: TemperType::default(),
}
}
}
impl std::fmt::Display for TemperDevice {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.t)
}
}
pub fn usb_detach(lvr_winusb: *mut libusb_device_handle, i_interface: i32) {
let ret;
unsafe {
ret = libusb_detach_kernel_driver(lvr_winusb, i_interface);
}
if ret == LIBUSB_ERROR_NOT_FOUND {
unsafe {
if DEBUG {
println!("Device already detached");
}
}
}
}
pub fn find_lvr_winusb(ctx: *mut *mut libusb_context, devices: &mut Vec<TemperDevice>) -> isize {
let mut devs_raw: *const *mut libusb_device = null_mut();
let cnt: usize;
unsafe { cnt = libusb_get_device_list(*ctx, &mut devs_raw) as usize };
if cnt < 1 {
println!("Could not find USB device: {}", cnt);
}
let mut i = 0usize;
let mut numdev = 0;
let devs_tmp;
unsafe {
devs_tmp = &*slice_from_raw_parts(devs_raw, cnt);
}
let devs: &mut [*mut libusb_device; 16] = &mut [null_mut(); 16];
for i in 0usize..cnt as usize {
devs[i] = devs_tmp[i];
}
while i < cnt && numdev < MAX_DEV {
let mut desc: libusb_device_descriptor;
/*let mut desc = libusb_device_descriptor {
bLength: 0,
bDescriptorType: 0,
bcdUSB: 0,
bDeviceClass: 0,
bDeviceSubClass: 0,
bDeviceProtocol: 0,
bMaxPacketSize0: 0,
idVendor: 0,
idProduct: 0,
bcdDevice: 0,
iManufacturer: 0,
iProduct: 0,
iSerialNumber: 0,
bNumConfigurations: 0,
};*/
unsafe {
desc = std::mem::zeroed();
}
let s;
unsafe {
s = libusb_get_device_descriptor(
devs[i],
&mut desc as *mut _ as *mut libusb_device_descriptor,
);
}
if s < 0 {
println!("Could not get USB device descriptor: {}", s);
i += 1;
continue;
}
unsafe {
for temper in TEMPERS {
if desc.idVendor == temper.vendor_id && desc.idProduct == temper.product_id {
let bus: u8;
let addr: u8;
let mut descmanu_b: [u8; 100] = [0; 100];
let mut descprod_b: [u8; 100] = [0; 100];
let mut descseri_b: [u8; 100] = [0; 100];
bus = libusb_get_bus_number(devs[i]);
addr = libusb_get_device_address(devs[i]);
let mut handle: *mut libusb_device_handle = null_mut();
let s = libusb_open(devs[i], &mut handle);
if s != 0 {
println!("error open {}", s);
}
libusb_get_string_descriptor_ascii(
handle,
desc.iManufacturer,
descmanu_b.as_mut_ptr(),
256,
);
libusb_get_string_descriptor_ascii(
handle,
desc.iProduct,
descprod_b.as_mut_ptr(),
256,
);
libusb_get_string_descriptor_ascii(
handle,
desc.iSerialNumber,
descseri_b.as_mut_ptr(),
256,
);
let descmanu: &CStr = CStr::from_bytes_until_nul(&descmanu_b).unwrap();
let descprod: &CStr = CStr::from_bytes_until_nul(&descprod_b).unwrap();
let descseri: &CStr = CStr::from_bytes_until_nul(&descseri_b).unwrap();
let mut device = TemperDevice::default();
if temper.check_product_name {
if descprod.to_str().unwrap() == temper.product_name {
device.handle = &mut handle;
device.t = temper;
devices.push(device);
} else {
libusb_close(handle);
continue;
}
} else {
device.handle = &mut handle;
device.t = temper;
devices.push(device);
}
if DEBUG {
println!(
"{} {} {} {} {} {} {}",
bus,
addr,
desc.idVendor,
desc.idProduct,
descmanu.to_str().unwrap(),
descprod.to_str().unwrap(),
descseri.to_str().unwrap()
);
}
numdev += 1;
break;
}
}
}
i += 1;
}
numdev as isize
}
pub fn setup_libusb_access(
ctx: &mut *mut libusb_context,
devices: &mut Vec<TemperDevice>,
) -> isize {
let numdev;
unsafe {
{
let res = libusb_init(ctx);
if res != 0 {
println!("Error code {res}: failed");
return -1;
}
}
numdev = find_lvr_winusb(ctx, devices);
}
if numdev < 1 {
println!("Couldn't find the USB device, Exiting: {}", numdev);
return -1;
}
for device in devices.iter() {
let handle = device.handle;
unsafe {
usb_detach(*handle, INTERFACE1);
usb_detach(*handle, INTERFACE2);
}
let cfg;
unsafe {
libusb_reset_device(*device.handle);
cfg = libusb_set_configuration(*device.handle, 0x01);
}
if cfg < 0 {
println!("Could not set configuration 1");
return -1;
}
let mut s;
unsafe { s = libusb_claim_interface(*device.handle, INTERFACE1) }
if s < 0 {
println!("Could not claim interface. Error: {}", s);
return -1;
}
unsafe { s = libusb_claim_interface(*device.handle, INTERFACE2) }
if s < 0 {
println!("Could not claim interface. Error: {}", s);
return -1;
}
}
numdev as isize
}
#[allow(unused_variables)]
pub fn ini_control_transfer(dev: &mut TemperDevice) {
let r;
let mut question: [u8; REQINTLEN] = [0; REQINTLEN];
question[0] = 0x01;
question[1] = 0x01;
unsafe {
r = libusb_control_transfer(
*dev.handle,
0x21,
0x09,
0x0201,
0x00,
question.as_mut_ptr(),
REQINTLEN as u16,
TIMEOUT,
);
}
if r < 0 {
println!("USB control write")
}
}
#[allow(unused_variables)]
pub fn control_transfer(dev: &mut TemperDevice, pquestion: &[u8; 8]) {
let r;
let mut question = pquestion.clone();
let question: *mut u8 = question.as_mut_ptr();
unsafe {
r = libusb_control_transfer(
*dev.handle,
0x21,
0x09,
0x0200,
0x01,
question,
REQINTLEN as u16,
TIMEOUT,
);
}
if r < 0 {
println!("USB control write")
}
}
pub fn interrupt_read(dev: &mut TemperDevice, data: &mut [u8; 100]) {
let (s, _i): (i32, i32);
let mut transferred: i32 = 0i32;
unsafe {
s = libusb_interrupt_transfer(
*dev.handle,
ENDPOINT_INT_IN,
data.as_mut_ptr(),
REQINTLEN as i32,
&mut transferred,
TIMEOUT,
);
}
if transferred != REQINTLEN as i32 {
println!("USB read failed: {}", s);
}
}
pub fn cleanup_usb_devices(ctx: &mut *mut libusb_context, devices: &mut Vec<TemperDevice>) {
for device in devices {
unsafe {
libusb_release_interface(*device.handle, INTERFACE1);
libusb_release_interface(*device.handle, INTERFACE2);
libusb_close(*device.handle);
}
}
unsafe {
libusb_exit(*ctx);
}
}
pub fn get_temp_r() -> String {
let mut ctx: libusb_context = unsafe { std::mem::zeroed() };
let mut ctx = &mut ctx as *mut _ as *mut libusb_context;
let mut answer: &mut [u8; 100] = &mut [0; 100];
let mut tempd: &mut [f32; 2] = &mut [0.; 2];
let calibration: &[f32; 2] = &[1., 0.];
let mut results: Vec<String> = vec![];
let output: String;
let mut devices: Vec<TemperDevice> = vec![];
setup_libusb_access(&mut ctx, &mut devices);
for device in devices.iter_mut() {
unsafe {
if DEBUG {
println!("{:?}", device.t);
}
}
control_transfer(device, &UTEMPERATURE);
interrupt_read(device, &mut answer);
device.t.decode(&answer, &mut tempd, calibration);
results.push(format!("{}", tempd[0]));
}
cleanup_usb_devices(&mut ctx, &mut devices);
output = results.join(",");
return output;
}