-
Notifications
You must be signed in to change notification settings - Fork 13
/
wensn.py
100 lines (78 loc) · 3.14 KB
/
wensn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import usb.core
# Inspired by ebswift, https://www.ebswift.com/reverse-engineering-spl-usb.html
# The Wensn WS1381 answers these bRequests
# 1 seems to be constant - array of 2 bytes returned
# 2 readMode - array of 1 byte returned
# 3 setMode - array of 1 byte returned
# 4 read SPL - array of 2 bytes returned
# 82 array of 4 bytes returned
ranges = ["30-80", "40-90", "50-100", "60-110", "70-120", "80-130", "30-130"]
speeds = ["fast", "slow"]
weights = ["A", "C"]
maxModes = ["instant", "max"]
def connect():
dev = usb.core.find(idVendor=0x16c0, idProduct=0x5dc)
assert dev is not None, "Is your sound meter plugged in to USB?"
print(dev)
return dev
def readBRequest(dev, bRequest):
ret = dev.ctrl_transfer(0xC0, bRequest, 0, 10, 200)
print(ret),
for elem in ret:
print(format(elem, '#010b')),
print
def readMode(dev):
ret = dev.ctrl_transfer(0xC0, 2, 0, 10, 200)
#print(ret)
#print(format(ret[0], '#010b'))
rangeN = (ret[0]&7) # bits 1,2,3 in ret[0] return rangeN from 0 to 6
weightN = (ret[0]&8)>>3 # bit 3 in ret[0] returns weight
speedN = (ret[0]&16)>>4 # bit 4 in ret[0] returns speed
maxModeN = (ret[0]&32)>>5 # bit 5 in ret[0] returns maxMode
return(ranges[rangeN], weights[weightN],
speeds[speedN], maxModes[maxModeN])
def setMode(dev, range="30-130", speed="slow", weight="A", maxMode="instant"):
rangeN = ranges.index(range)
speedN = speeds.index(speed)
weightN = weights.index(weight)
maxModeN = maxModes.index(maxMode)
print("setMode: range:%s weight:%s speed:%s maxMode:%s" %
(range, weight, speed, maxMode))
wvalue = rangeN | (weightN&1)<<3 | (speedN&1)<<4 | (maxModeN&1)<<5
# Function of bits 6 and 7 is unknown (nothing?)
dev.ctrl_transfer(0xC0, 3, wvalue, 0, 200)
peak = 0
def readSPL(dev):
global peak
ret = dev.ctrl_transfer(0xC0, 4, 0, 10, 200) # wvalue (3rd arg) is ignored
#print(ret)
#print(format(ret[1], '#010b'))
rangeN = (ret[1]&28)>>2 # bits 2,3,4 in ret[1] return rangeN from 0 to 6
weightN = (ret[1]&32)>>5 # bit 5 in ret[1] return weightN
speedN = (ret[1]&64)>>6 # bit 6 in ret[1] return speedN
# bit 7 seems to alternate every 1 second?
dB = (ret[0] + ((ret[1] & 3) * 256)) * 0.1 + 30
if dB > peak:
peak = dB
return(dB, ranges[rangeN], weights[weightN], speeds[speedN])
if __name__ == "__main__":
import logroll
import datetime
import time
# connect to WS1381 over USB
dev = connect()
# set default modes: range="30-130", speed="slow", weight="A", maxMode="instant"
setMode(dev)
log = logroll.LogRoll(logdir="logs")
while True:
now = datetime.datetime.now()
# roll over to a new log whenever the filename changes - in this case, every hour.
log.open_or_reopen(now.strftime('%Y-%m-%d-%H-%M.log'))
dB, range, weight, speed = readSPL(dev)
print("%.2f,%s,%s,%s"
% (dB, weight, speed, now.strftime('%Y,%m,%d,%H,%M,%S')),
file = log.fp)
print("%.2f,%s,%s,%s"
% (dB, weight, speed, now.strftime('%Y,%m,%d,%H,%M,%S')))
log.fp.flush()
time.sleep(1)