Created
December 20, 2021 05:49
-
-
Save classilla/4b8780e853e4d93eba8fa5ef789d9c47 to your computer and use it in GitHub Desktop.
Linux code for reading a GM1356 USB-based decibel sound monitor. See https://oldvcr.blogspot.com/2021/12/monitoring-vintage-server-room-and.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
(C)2020-1 Cameron Kaiser, ckaiser@floodgap.com | |
All rights reserved. | |
Distributed under the Floodgap Free Software License. | |
Credit to https://github.com/dobra-noc/gm1356/blob/master/PROTOCOL.md for the | |
original protocol description. | |
Linux: | |
gcc -o gm1356 gm1356.c -lusb | |
This device doesn't register as a HID on Mac OS X (polling time of 0?!). | |
This device freaks out NetBSD and messes with the console. | |
Even Linux's libhid doesn't like it, so we have to talk to it the hard way. | |
*/ | |
#define DEBUG 0 | |
#define DSLM_VENDID 0x64bd | |
#define DSLM_DEVID 0x74e3 | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <getopt.h> | |
#define SEND_PACKET_LENGTH 8 | |
unsigned char PACKET[SEND_PACKET_LENGTH] = { | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
}; | |
int ret; | |
/* #if defined(__linux__) */ | |
#include <usb.h> | |
/* this is written like this in the hopes that there will be ports to | |
other operating systems, but this device is a piece of crap and has | |
stymied all of my current attempts. */ | |
struct usb_bus *busses; | |
struct usb_bus *bus; | |
struct usb_device *dev, *dslm = NULL; | |
struct usb_dev_handle *hdslm; | |
void release_dslm_handle() { | |
(void)usb_release_interface(hdslm, 1); | |
(void)usb_close(hdslm); | |
} | |
int claim_dslm_handle() { | |
if (DEBUG) | |
usb_set_debug(255); | |
usb_init(); | |
usb_find_busses(); | |
ret = usb_find_devices(); | |
if (ret < 0) { | |
perror("usb_find_devices"); | |
return 1; | |
} | |
busses = usb_get_busses(); | |
for(bus = busses; bus; bus = bus->next) { | |
for(dev = bus->devices; dev; dev = dev->next) { | |
if ((dev->descriptor.idVendor == DSLM_VENDID) && | |
(dev->descriptor.idProduct == DSLM_DEVID)) { | |
dslm = dev; | |
} | |
} | |
} | |
if (!dslm) { | |
fprintf(stderr, "unable to find DSLM\n"); | |
return 1; | |
} | |
hdslm = usb_open(dslm); | |
usb_detach_kernel_driver_np(hdslm, 0); | |
ret = usb_claim_interface(hdslm, 0); | |
if (ret < 0) { | |
release_dslm_handle(); | |
perror("usb_claim_interface"); | |
return 1; | |
} | |
return 0; | |
} | |
/* | |
int usb_interrupt_write(usb_dev_handle *dev, int ep, const char *bytes, | |
int size, int timeout); | |
*/ | |
int send_dslm_packet() { | |
ret = usb_interrupt_write( | |
hdslm, | |
0x02, /* endpoint 2 OUT */ | |
(const char *)PACKET, | |
SEND_PACKET_LENGTH, | |
10000); | |
if (DEBUG) { | |
fprintf(stderr, "usb_interrupt_write: %d\n", ret); | |
if (ret != SEND_PACKET_LENGTH) | |
return 1; | |
} else if (ret != SEND_PACKET_LENGTH) { | |
fprintf(stderr, "usb_interrupt_write: %d\n", ret); | |
return 1; | |
} | |
return 0; | |
} | |
/* | |
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, | |
int timeout); | |
*/ | |
int get_dslm_report() { | |
ret = usb_interrupt_read( | |
hdslm, | |
0x81, /* endpoint 1 IN */ | |
(char *)PACKET, | |
SEND_PACKET_LENGTH, | |
10000); | |
if (DEBUG) { | |
fprintf(stderr, "usb_interrupt_read: %d\n", ret); | |
} | |
return ret; | |
} | |
/* #endif */ | |
void usage(char **argv) { | |
fprintf(stderr, "usage: %s [-s] [-c] [-m] [-r 0-4]\n", argv[0]); | |
} | |
int main(int argc, char** argv) { | |
int ch; | |
size_t tries = 0; | |
float db, maxdb = 130.0f; | |
long r; | |
/* send settings */ | |
PACKET[0] = 0x56; | |
PACKET[1] = 0x40; /* filter A, not max, fast, full 30-130dB range */ | |
while ((ch = getopt(argc, argv, "?hr:csm")) != -1) { | |
switch(ch) { | |
case 's': { | |
/* use 1 second averaged sample, not instant */ | |
PACKET[1] &= 0xbf; /* turn off fast bit */ | |
break; | |
} | |
case 'c': { | |
/* use low-pass filter "filter C" */ | |
PACKET[1] |= 0x10; /* turn on C bit */ | |
break; | |
} | |
case 'm': { | |
/* return max reading rather than current */ | |
PACKET[1] |= 0x20; /* turn on max bit */ | |
break; | |
} | |
case 'r': { | |
/* set decibel range for greater precision */ | |
/* | |
0: 30-130dB range | |
1: 30-60dB | |
2: 50-100dB | |
3: 60-110dB | |
4: 80-130dB | |
*/ | |
ret = atoi(optarg); | |
if (ret < 0 || ret > 4) { | |
fprintf(stderr, "%s: -r 0-4 only\n", | |
argv[0]); | |
return 1; | |
} | |
maxdb = | |
(maxdb == 1) ? 60 : | |
(maxdb == 2) ? 100 : | |
(maxdb == 3) ? 110 : | |
130; | |
PACKET[1] |= ret; | |
break; | |
} | |
case '?' : | |
case 'h' : | |
default: { | |
usage(argv); | |
return 0; | |
} | |
} | |
} | |
if (claim_dslm_handle()) | |
return 1; | |
if (send_dslm_packet()) | |
return 1; | |
/* request dB */ | |
PACKET[0] = 0xb3; | |
/* needs a random ID number */ | |
r = random(); | |
PACKET[1] = r & 0xff; | |
PACKET[2] = ( r >> 8 ) & 0xff; | |
PACKET[3] = ( r >>16 ) & 0xff; | |
if (DEBUG) { | |
for(ret=0;ret<8;ret++) { | |
fprintf(stderr, "%02x ", PACKET[ret]); | |
} | |
} | |
for(;;) { | |
/* sometimes have to try this a few times */ | |
if (send_dslm_packet()) | |
return 1; | |
if (get_dslm_report() == SEND_PACKET_LENGTH) { | |
if (DEBUG) { | |
for(ret=0;ret<8;ret++) { | |
fprintf(stderr, "%02x ", PACKET[ret]); | |
} | |
} | |
/* check for preposterous values: cannot be > range */ | |
db = ((256*PACKET[0]) + PACKET[1]) / 10.0f; | |
if (db <= maxdb) | |
break; | |
if (DEBUG) | |
fprintf(stderr, "preposterous value %2.1f\n", | |
db); | |
} | |
if (++tries > 8) { | |
fprintf(stderr, "read failed\n"); | |
release_dslm_handle(); | |
return 1; | |
} | |
} | |
fprintf(stdout, "%2.1f\n", db); | |
release_dslm_handle(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment