nimRum 1.1.0__py3-none-linux_armv7l.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nimRum/__init__.py ADDED
File without changes
nimRum/gitStatus.txt ADDED
@@ -0,0 +1,5 @@
1
+ de16b7a22cec6d111ba61684835e757dfcd8fc7b
2
+ On branch master
3
+ Your branch is up to date with 'origin/master'.
4
+
5
+ nothing to commit, working tree clean
Binary file
Binary file
Binary file
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/python3
2
+
3
+ #/******************************************************************************
4
+ # * COPYRIGHT (c) 2021-2025, AbtAudio AB, All rights reserved.
5
+ # *
6
+ # * The copyright to the computer program(s) herein is the property of
7
+ # * AbtAudio AB. The computer programs(s) may implement properties protected by
8
+ # * patent(s) such as arising from SE544478C2, US12034828B2 or WO2021/220149.
9
+ # *
10
+ # * Redistribution in any form, with or without modification, is only permitted
11
+ # * with the written permission from AbtAudio AB.
12
+ # *
13
+ # * The computer program(s) may be used for private purposes and for evaluation
14
+ # * purposes.
15
+ # *
16
+ # * The computer program(s) may NOT be used for any commercial purposes without
17
+ # * the written permission from AbtAudio AB.
18
+ # *
19
+ # * The computer program(s) are provided as is, without any warranties, but
20
+ # * feedback in form of suggestions for improvements is encouraged.
21
+ # ******************************************************************************/
22
+
23
+ import platform
24
+
25
+ """
26
+ This is kind of a placeholder for future development
27
+ """
28
+ class nimRumCheckHW:
29
+ def __init__(self):
30
+ print(platform.uname())
31
+ self.cpuArch = platform.machine()
32
+ self.testHW()
33
+
34
+ def testHW(self):
35
+ if self.cpuArch not in ['aarch64', 'armv6l', 'armv7l']:
36
+ print("Platform not supported")
37
+ quit()
38
+
39
+ return True
40
+
41
+ if __name__ == "__main__":
42
+ t = nimRumCheckHW()
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/python3
2
+
3
+ #/******************************************************************************
4
+ # * COPYRIGHT (c) 2021-2025, AbtAudio AB, All rights reserved.
5
+ # *
6
+ # * The copyright to the computer program(s) herein is the property of
7
+ # * AbtAudio AB. The computer programs(s) may implement properties protected by
8
+ # * patent(s) such as arising from SE544478C2, US12034828B2 or WO2021/220149.
9
+ # *
10
+ # * Redistribution in any form, with or without modification, is only permitted
11
+ # * with the written permission from AbtAudio AB.
12
+ # *
13
+ # * The computer program(s) may be used for private purposes and for evaluation
14
+ # * purposes.
15
+ # *
16
+ # * The computer program(s) may NOT be used for any commercial purposes without
17
+ # * the written permission from AbtAudio AB.
18
+ # *
19
+ # * The computer program(s) are provided as is, without any warranties, but
20
+ # * feedback in form of suggestions for improvements is encouraged.
21
+ # ******************************************************************************/
22
+
23
+ import numpy as np
24
+ import matplotlib.pyplot as plt
25
+ import wavio
26
+ import time
27
+ import statistics
28
+ from pathlib import Path
29
+ import os
30
+
31
+ class NIMRUM_MEAS_SPIKES():
32
+
33
+ def __init__(self, capRate=48000, maxTime_sec=200, maxDiff_us=250*1000, maxInt=1, resultFolder=None):
34
+ self.capRate = capRate
35
+ self.maxDiff_us = maxDiff_us
36
+ self.trigMinLvl = maxInt / 500
37
+
38
+ self.synchDiff_X = np.array([])
39
+ self.synchDiff_Y = np.array([])
40
+ self.rXArr = np.array([])
41
+ self.lXArr = np.array([])
42
+
43
+ self.maxTime_sec = maxTime_sec # To limit size of stored data
44
+ self.currentTime_sec = 0.0
45
+
46
+ self.storeInterval_sec = 10*60
47
+
48
+ self.plotTitle = "Synch Diff - Px VS Py"
49
+ plotFileName = self.plotTitle.replace(" ", "_") + ".pdf"
50
+ if resultFolder == None:
51
+ resultFolder = str(Path.home())
52
+ self.plotFileName = os.path.join(resultFolder, plotFileName)
53
+ self.plotLabel = "Px VS Py"
54
+
55
+ self.lastStorageTime = time.time()
56
+
57
+ def storeResult(self):
58
+ if len(self.synchDiff_X) == 2:
59
+ print("No result to store")
60
+ return
61
+
62
+ ax1 = plt.subplot(111)
63
+ ax1.clear()
64
+
65
+ ax1.plot(self.synchDiff_X, self.synchDiff_Y, label=self.plotLabel, color="black")#, marker=".")
66
+
67
+ ax1.set_title(self.plotTitle)
68
+ ax1.set_xlabel("Time [s]")
69
+ ax1.set_ylabel("Channel accuracy [us]")
70
+ #ax1.set_ylim(-550, 550)
71
+
72
+ plt.savefig(self.plotFileName, format="pdf", bbox_inches="tight")
73
+
74
+ npyFileName = self.plotFileName+'.npy'
75
+ with open(npyFileName, 'wb') as f:
76
+ np.save(f, self.synchDiff_X)
77
+ np.save(f, self.synchDiff_Y)
78
+
79
+ print("Stored: {} and {}".format(self.plotFileName, npyFileName))
80
+
81
+ def _limitdata(self):
82
+ """
83
+ Just keep latest latest self.maxTime_sec seconds
84
+ In case not spikes detected for a long time, or at least 20 data points
85
+ """
86
+ while (self.currentTime_sec > self.maxTime_sec) and (len(self.synchDiff_X) > 20):
87
+ self.currentTime_sec -= self.synchDiff_X[0]
88
+ self.synchDiff_X -= self.synchDiff_X[0]
89
+
90
+ self.synchDiff_X = np.delete(self.synchDiff_X, 0)
91
+ self.synchDiff_Y = np.delete(self.synchDiff_Y, 0)
92
+
93
+ self.rXArr = np.delete(self.rXArr, 0)
94
+ self.lXArr = np.delete(self.lXArr, 0)
95
+
96
+ def add(self, indata):
97
+ capR = indata[:,0]
98
+ capL = indata[:,1]
99
+
100
+ capRSpikeIdxs = self.getSpikeIdxs(capR)
101
+ capLSpikeIdxs = self.getSpikeIdxs(capL)
102
+
103
+ capRIdxs, capLIdxs, diffXVals = self.removeUnmatchedSpikes(
104
+ capRSpikeIdxs, capLSpikeIdxs
105
+ )
106
+
107
+ if (capRIdxs.size!=0) and (capLIdxs.size!=0):
108
+
109
+ rX = self.approxZeroCrossing(capR, capRIdxs)
110
+ lX = self.approxZeroCrossing(capL, capLIdxs)
111
+
112
+ synchDiffTime_us = rX - lX
113
+
114
+ # This just stored what can be plotted/stored to file
115
+ self.synchDiff_X = np.append(self.synchDiff_X, self.currentTime_sec + (np.array(capRIdxs)/float(self.capRate)) )
116
+ self.synchDiff_Y = np.append(self.synchDiff_Y, list(synchDiffTime_us))
117
+
118
+ if (len(self.rXArr) > 3) and (len(self.lXArr) > 3):
119
+ # TODO: This must be improved
120
+ rD = (rX-self.rXArr[-1]) - np.round(np.median(np.diff(self.rXArr)))
121
+ lD = (lX-self.lXArr[-1]) - np.round(np.median(np.diff(self.lXArr)))
122
+
123
+ meanY = statistics.mean(self.synchDiff_Y)
124
+ else:
125
+ rD = [0]
126
+ lD = [0]
127
+
128
+ meanY = 0.0
129
+
130
+ self.rXArr = np.append(self.rXArr, rX)
131
+ self.lXArr = np.append(self.lXArr, lX)
132
+
133
+ # TODO: This script will soon need cleanup. This is to avoid when captured sample array wraps
134
+ if np.abs(rD) > 500000 and np.abs(lD) > 500000 and len(self.rXArr) > 1:
135
+ self.rXArr = np.delete(self.rXArr, 0)
136
+ self.lXArr = np.delete(self.lXArr, 0)
137
+
138
+ sTimeInt = int(np.round(synchDiffTime_us[0]))
139
+ print("synchDiffTime_us: {:4d} Mean: {:4.0f} DistanceToMean: {:4.0f} Diff R/L: {:4.0f}/{:4.0f} (R-L={:4.0f})".format(
140
+ sTimeInt, np.round(meanY), np.round(sTimeInt - meanY), rD[0], lD[0], rD[0]-lD[0]))
141
+
142
+ self.currentTime_sec += ( float(len(capR)) / float(self.capRate) )
143
+ self._limitdata()
144
+
145
+ if (self.lastStorageTime + self.storeInterval_sec) < time.time():
146
+ print("Storing to file every {}s".format(self.storeInterval_sec))
147
+ self.storeResult()
148
+ self.lastStorageTime = time.time()
149
+
150
+
151
+ def getSpikeIdxs(self, din):
152
+ """
153
+ Return index where input array is about to cross 0 with highest gradient
154
+ Expects about one spike per capture
155
+ Only returns max 1 peak
156
+ """
157
+
158
+ # Detect if too low signal
159
+ trigLvl = np.max(din)/2
160
+ highValArr = np.where(din > trigLvl)[0]
161
+
162
+ #if (len(highValArr) > len(din)/500) or (trigLvl < self.trigMinLvl):
163
+ if trigLvl < self.trigMinLvl:
164
+ print("Just noise? High Samples:{}/{} TrigLvl:{}<{}".format(len(highValArr), len(din), trigLvl, self.trigMinLvl))
165
+ return np.array([])
166
+
167
+ # Float to ensure no overflow when retreiving diff
168
+ #dinF = din.astype("float64")
169
+
170
+ # Get where din is passing 0, while 'going up'
171
+ a = np.gradient(din)
172
+ resIdx = np.argmax(a)
173
+
174
+ # Want to get the idx of the last negative valued sample before crossing 0
175
+ while (din[resIdx] > 0) and (resIdx > 0):
176
+ resIdx -= 1
177
+ if resIdx == 0:
178
+ print("Max gradient at fishy position")
179
+ return np.array([])
180
+
181
+ # Double check we are in the middle of a square wave
182
+ # Some soundcards have strong overshoot from the transient
183
+ w = 10
184
+ ok = True
185
+ numOfHigh = (din[resIdx+1:resIdx+w+1] >= 0).sum()
186
+ numOfLow = (din[resIdx-w:resIdx] < 0).sum()
187
+ if (numOfHigh != w):
188
+ ok = False
189
+ if (numOfLow != w):
190
+ ok = False
191
+
192
+ if ok == False:
193
+ print("Failed 'middle of square' check. H/L: {}/{}".format(numOfLow, numOfHigh))
194
+ return np.array([])
195
+
196
+
197
+ return np.array([resIdx])
198
+
199
+
200
+ def removeUnmatchedSpikes(self, rIxds, lIdxs):
201
+ """
202
+ Compare two arrays with indexes.
203
+ Return two arrays where indexes with too large diff has been removed
204
+ TODO: This function made more sense when getSpikeIdxs could return multiple indexes
205
+ """
206
+ maxAllowedDiff = (self.maxDiff_us * self.capRate) / 1000000
207
+ rRes = []
208
+ lRes = []
209
+ xRes = [] # X-values for kept indexes
210
+
211
+ maxCnt = min(len(rIxds), len(lIdxs))
212
+ idx = 0
213
+ while idx < maxCnt:
214
+ rVal = rIxds[idx]
215
+ lVal = lIdxs[idx]
216
+ idxDiff = rVal - lVal
217
+
218
+ # Spikes seems missing in R
219
+ if idxDiff > maxAllowedDiff:
220
+ idx += 2
221
+ print("Skipped L")
222
+ continue
223
+ # Seems to be missing from L
224
+ if idxDiff < -maxAllowedDiff:
225
+ idx += 2
226
+ print("Skipped R")
227
+ continue
228
+
229
+ rRes.append(rIxds[idx])
230
+ lRes.append(lIdxs[idx])
231
+ xRes.append(idx)
232
+ idx += 1
233
+
234
+ return np.asarray(rRes), np.asarray(lRes), np.asarray(xRes)
235
+
236
+
237
+ def approxZeroCrossing(self, dinArrInt, dinArrXPrevCross):
238
+ """
239
+ Returns X values in us where zero corrings occur in us.
240
+ Linear approximation
241
+ """
242
+ timePerSample = 1000000.0 / float(self.capRate)
243
+
244
+ # Float to ensure no overflow when retreiving diff
245
+ dinArr = dinArrInt.astype("float64")
246
+
247
+ newX = []
248
+ for idx in dinArrXPrevCross:
249
+ k = (dinArr[idx + 1] - dinArr[idx])
250
+ k /= timePerSample
251
+
252
+ zeroYatX = (idx * timePerSample) - (dinArr[idx] / k)
253
+
254
+ newX.append(zeroYatX) # round(zeroYatX) )
255
+
256
+ return np.asarray(newX)
257
+
258
+
259
+
260
+
261
+ def main():
262
+ import sys
263
+
264
+ f = wavio.read(sys.argv[1])
265
+ print("Opened: {} ({},{})".format(sys.argv[1], f.rate, f.sampwidth))
266
+
267
+ o = NIMRUM_MEAS_SPIKES(capRate=f.rate)
268
+ o.add(f.data)
269
+
270
+ o.storeResult()
271
+ plt.show()
272
+
273
+ if __name__ == '__main__':
274
+ main()
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/python3
2
+
3
+ #/******************************************************************************
4
+ # * COPYRIGHT (c) 2021-2025, AbtAudio AB, All rights reserved.
5
+ # *
6
+ # * The copyright to the computer program(s) herein is the property of
7
+ # * AbtAudio AB. The computer programs(s) may implement properties protected by
8
+ # * patent(s) such as arising from SE544478C2, US12034828B2 or WO2021/220149.
9
+ # *
10
+ # * Redistribution in any form, with or without modification, is only permitted
11
+ # * with the written permission from AbtAudio AB.
12
+ # *
13
+ # * The computer program(s) may be used for private purposes and for evaluation
14
+ # * purposes.
15
+ # *
16
+ # * The computer program(s) may NOT be used for any commercial purposes without
17
+ # * the written permission from AbtAudio AB.
18
+ # *
19
+ # * The computer program(s) are provided as is, without any warranties, but
20
+ # * feedback in form of suggestions for improvements is encouraged.
21
+ # ******************************************************************************/
22
+
23
+ import argparse
24
+ import signal
25
+ import numpy as np
26
+
27
+ import sounddevice
28
+ import wavio
29
+ from pathlib import Path
30
+ import os
31
+
32
+ from nimRum import nimRumMeasSpikes
33
+
34
+ """
35
+ sudo pip3 install sounddevice
36
+ sudo apt-get install libportaudio2
37
+ sudo apt-get install libopenblas-dev
38
+ """
39
+
40
+ class NIMRUM_MEAS():
41
+
42
+ def __init__(self, cfg, maxTime_sec=5*60):
43
+ self.cfg = cfg
44
+ self.maxTime_sec = float(maxTime_sec)
45
+ self.dataEmpty = True
46
+
47
+ self.dataFileName = os.path.join(self.cfg['resultFolder'], "nimRumMeas.wav")
48
+
49
+ if self.cfg['measMode'] == 'synchErr':
50
+ self.measType = nimRumMeasSpikes.NIMRUM_MEAS_SPIKES(capRate=self.cfg['sampleRate'], maxTime_sec=60*60, maxInt=self.cfg['maxInt'], resultFolder=self.cfg['resultFolder'])
51
+ else:
52
+ print("ERROR: Unknown measure type: {}".format(capRate=self.cfg['measMode']))
53
+
54
+ def _limitdata(self):
55
+ blockSize = int(self.cfg['sampleRate'] * self.cfg['interval'])
56
+
57
+ while (float(self.data.shape[0]) / float(self.cfg['sampleRate'])) > self.maxTime_sec:
58
+ self.data = np.delete(self.data, np.s_[0:blockSize], axis=0)
59
+
60
+ def add(self, indata):
61
+ if self.dataEmpty or not self.cfg['storeData']:
62
+ self.data = indata
63
+ self.dataEmpty = False
64
+ else:
65
+ self.data = np.concatenate((self.data, indata), axis=0)
66
+ self._limitdata()
67
+
68
+ # TODO: This behavior depends on measType...
69
+ self.measType.add(indata)
70
+
71
+ def storeData(self):
72
+ wavio.write(self.dataFileName, self.data, self.cfg['sampleRate'], sampwidth=self.cfg['sampW'])
73
+ print("Stored: {} (Rate:{} SampleSize:{} Shape:{} )".format(self.dataFileName, self.cfg['sampleRate'], self.cfg['sampW'], self.data.shape))
74
+
75
+ def storeResult(self):
76
+ self.measType.storeResult()
77
+
78
+ def getCfg():
79
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
80
+
81
+ parser.add_argument('--listDevices', '-l', action="store_true", help='List audio devices')
82
+ parser.add_argument('--device', '-d', default=0, help='Input device ID')
83
+ parser.add_argument('--interval', '-i', type=float, default=1.0, help='Capture interval: Seconds')
84
+ parser.add_argument('--sampleRate', '-f', type=float, default=48000, help='Sample rate: 0=Use device default')
85
+ parser.add_argument('--sampleSize', '-s', type=str, default='int32', help='Sample size: float32|int32|int16|int8|uint8')
86
+ parser.add_argument('--measMode', '-m', type=str, default='synchErr', help='Meaure mode: synchErr|chirp|...')
87
+ parser.add_argument('--storeData', '-S', action="store_true", help='Store all collected data to file')
88
+ parser.add_argument('--resultFolder', '-R', default='/home/pi/LOGS', help='Folder where measurements are stored')
89
+
90
+ args = parser.parse_args()
91
+
92
+ if args.listDevices:
93
+ print(sounddevice.query_devices())
94
+ quit()
95
+
96
+ if args.sampleRate == 0:
97
+ args.sampleRate = sounddevice.query_devices(args.device, 'input')['default_samplerate']
98
+
99
+ cfg = vars(args) # Convert to dict
100
+
101
+ cfg['sampW'] = 0
102
+ if args.sampleSize == 'int32':
103
+ cfg['sampW'] = 4
104
+ cfg['maxInt'] = 2147483647
105
+ elif args.sampleSize == 'int16':
106
+ cfg['sampW'] = 2
107
+ cfg['maxInt'] = 32767
108
+ else:
109
+ print("ERROR: Only supports int32 or int16, not {}".format(args.sampleSize))
110
+ quit()
111
+
112
+ return cfg
113
+
114
+
115
+ def signal_handler(sig, frame):
116
+ print("Catched Ctrl-C")
117
+ global storeData
118
+ global measObj
119
+ global run
120
+ global alreadyClosing
121
+
122
+ run = False
123
+
124
+ if not alreadyClosing:
125
+ alreadyClosing = True
126
+
127
+ if storeData:
128
+ measObj.storeData()
129
+
130
+ measObj.storeResult()
131
+
132
+
133
+ def callBack(indata, frames, time, status):
134
+ global measObj
135
+
136
+ if status:
137
+ print("Got callback status:{}".format(status))
138
+
139
+ #print("CAPTURES: ", indata.shape, frames, time)
140
+ measObj.add(indata)
141
+
142
+ def main():
143
+ signal.signal(signal.SIGINT, signal_handler)
144
+
145
+ global storeData
146
+ global measObj
147
+ global run
148
+ global alreadyClosing
149
+
150
+ cfg = getCfg()
151
+ storeData = cfg['storeData']
152
+
153
+ measObj = NIMRUM_MEAS(cfg)
154
+ run = True
155
+ alreadyClosing = False
156
+
157
+ blockSize = int(cfg['sampleRate'] * cfg['interval'])
158
+
159
+ with sounddevice.InputStream(device=cfg['device'], channels=2, dtype=cfg['sampleSize'], callback=callBack,
160
+ blocksize=blockSize, samplerate=cfg['sampleRate']):
161
+ while run:
162
+ pass
163
+
164
+
165
+ if __name__ == '__main__':
166
+ main()
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/python3
2
+
3
+ #/******************************************************************************
4
+ # * COPYRIGHT (c) 2021-2025, AbtAudio AB, All rights reserved.
5
+ # *
6
+ # * The copyright to the computer program(s) herein is the property of
7
+ # * AbtAudio AB. The computer programs(s) may implement properties protected by
8
+ # * patent(s) such as arising from SE544478C2, US12034828B2 or WO2021/220149.
9
+ # *
10
+ # * Redistribution in any form, with or without modification, is only permitted
11
+ # * with the written permission from AbtAudio AB.
12
+ # *
13
+ # * The computer program(s) may be used for private purposes and for evaluation
14
+ # * purposes.
15
+ # *
16
+ # * The computer program(s) may NOT be used for any commercial purposes without
17
+ # * the written permission from AbtAudio AB.
18
+ # *
19
+ # * The computer program(s) are provided as is, without any warranties, but
20
+ # * feedback in form of suggestions for improvements is encouraged.
21
+ # ******************************************************************************/
22
+
23
+ import sys
24
+ import signal
25
+ import socket
26
+ import re
27
+ import socket
28
+ import os
29
+ from nimRum import nimRumCheckHW
30
+
31
+ import netifaces as ni
32
+
33
+
34
+ class nimRumPyCommon:
35
+ def __init__(self, meName=os.path.basename(__file__)):
36
+
37
+ self.meStr = "**" + meName + "**: "
38
+
39
+ self.run = 1
40
+ signal.signal(signal.SIGINT, self.signal_handler)
41
+
42
+ try:
43
+ self.myName = socket.gethostname()
44
+ except:
45
+ self.myName = "Unknown1"
46
+
47
+ try:
48
+ # TODO: This is not failsafe. Expect all devices to be named 'prezoXX'
49
+ self.myId = int(re.findall(r"\d+", self.myName)[0])
50
+ except:
51
+ self.myId = 666
52
+
53
+ t = nimRumCheckHW.nimRumCheckHW()
54
+
55
+ def lclPrint(self, pStr):
56
+ print(self.meStr + pStr)
57
+ sys.stdout.flush()
58
+
59
+ def signal_handler(self, sig, frame):
60
+ self.lclPrint("Catched Ctrl-C, stopping")
61
+ self.run = 0
62
+
63
+ def getMyUniqueName(self):
64
+ return self.myName
65
+
66
+ def getMyUniqueId(self):
67
+ return self.myId
68
+
69
+ def getBCAddr(self, nicName):
70
+ try:
71
+ useLocalClock = 0
72
+ if nicName == "lo":
73
+ useLocalClock = 1
74
+ bcastAddr = "127.0.0.255"
75
+ else:
76
+ bcastAddr = ni.ifaddresses(nicName)[ni.AF_INET][0]["broadcast"]
77
+ except:
78
+ self.lclPrint("'nic' must be one of the following:")
79
+ self.lclPrint(str(ni.interfaces()))
80
+ quit()
81
+
82
+ self.lclPrint("BCAddr:" + str(bcastAddr))
83
+ return bcastAddr, useLocalClock
nimRum/nimRumPyLed.py ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/python3
2
+
3
+ #/******************************************************************************
4
+ # * COPYRIGHT (c) 2021-2025, AbtAudio AB, All rights reserved.
5
+ # *
6
+ # * The copyright to the computer program(s) herein is the property of
7
+ # * AbtAudio AB. The computer programs(s) may implement properties protected by
8
+ # * patent(s) such as arising from SE544478C2, US12034828B2 or WO2021/220149.
9
+ # *
10
+ # * Redistribution in any form, with or without modification, is only permitted
11
+ # * with the written permission from AbtAudio AB.
12
+ # *
13
+ # * The computer program(s) may be used for private purposes and for evaluation
14
+ # * purposes.
15
+ # *
16
+ # * The computer program(s) may NOT be used for any commercial purposes without
17
+ # * the written permission from AbtAudio AB.
18
+ # *
19
+ # * The computer program(s) are provided as is, without any warranties, but
20
+ # * feedback in form of suggestions for improvements is encouraged.
21
+ # ******************************************************************************/
22
+
23
+ try:
24
+ import platform
25
+ if platform.machine() == 'aarch64':
26
+ import wiringpi
27
+ else:
28
+ from gpiozero import LED
29
+ except:
30
+ pass
31
+
32
+ class nimRumPyLed:
33
+ def __init__(self, Rpin=12, Gpin=13, Bpin=26):
34
+
35
+ self.ledAvailable = False
36
+ try:
37
+ self.platform = platform.machine()
38
+ if self.platform == 'aarch64':
39
+ wiringpi.wiringPiSetup()
40
+ self.ledR = 24
41
+ self.ledG = 26
42
+ self.ledB = 25
43
+ else:
44
+ self.ledR = LED(Rpin)
45
+ self.ledG = LED(Gpin)
46
+ self.ledB = LED(Bpin)
47
+
48
+ self.ledAvailable = True
49
+ except:
50
+ print("nimRumPyLed NOT enabled, reading " + __file__ + " migth help")
51
+
52
+ self.off()
53
+
54
+ def off(self):
55
+ if self.ledAvailable:
56
+ if self.platform == 'aarch64':
57
+ wiringpi.pinMode(self.ledR, wiringpi.GPIO.INPUT)
58
+ wiringpi.pinMode(self.ledG, wiringpi.GPIO.INPUT)
59
+ wiringpi.pinMode(self.ledB, wiringpi.GPIO.INPUT)
60
+ else:
61
+ self.ledR.off()
62
+ self.ledG.off()
63
+ self.ledB.off()
64
+
65
+ def red(self):
66
+ if self.ledAvailable:
67
+ if self.platform == 'aarch64':
68
+ wiringpi.pinMode(self.ledR, wiringpi.GPIO.OUTPUT)
69
+ wiringpi.pinMode(self.ledG, wiringpi.GPIO.INPUT)
70
+ wiringpi.pinMode(self.ledB, wiringpi.GPIO.INPUT)
71
+ wiringpi.digitalWrite(self.ledR, wiringpi.GPIO.LOW)
72
+ else:
73
+ self.ledR.on()
74
+ self.ledG.off()
75
+ self.ledB.off()
76
+
77
+ def green(self):
78
+ if self.ledAvailable:
79
+ if self.platform == 'aarch64':
80
+ wiringpi.pinMode(self.ledR, wiringpi.GPIO.INPUT)
81
+ wiringpi.pinMode(self.ledG, wiringpi.GPIO.OUTPUT)
82
+ wiringpi.pinMode(self.ledB, wiringpi.GPIO.INPUT)
83
+ wiringpi.digitalWrite(self.ledG, wiringpi.GPIO.LOW)
84
+ else:
85
+ self.ledR.off()
86
+ self.ledG.on()
87
+ self.ledB.off()
88
+
89
+ def blue(self):
90
+ if self.ledAvailable:
91
+ if self.platform == 'aarch64':
92
+ wiringpi.pinMode(self.ledR, wiringpi.GPIO.INPUT)
93
+ wiringpi.pinMode(self.ledG, wiringpi.GPIO.INPUT)
94
+ wiringpi.pinMode(self.ledB, wiringpi.GPIO.OUTPUT)
95
+ wiringpi.digitalWrite(self.ledB, wiringpi.GPIO.LOW)
96
+ else:
97
+ self.ledR.off()
98
+ self.ledG.off()
99
+ self.ledB.on()
100
+
101
+ def white(self):
102
+ if self.ledAvailable:
103
+ if self.platform == 'aarch64':
104
+ wiringpi.pinMode(self.ledR, wiringpi.GPIO.OUTPUT)
105
+ wiringpi.digitalWrite(self.ledR, wiringpi.GPIO.LOW)
106
+ wiringpi.pinMode(self.ledG, wiringpi.GPIO.OUTPUT)
107
+ wiringpi.digitalWrite(self.ledG, wiringpi.GPIO.LOW)
108
+ wiringpi.pinMode(self.ledB, wiringpi.GPIO.OUTPUT)
109
+ wiringpi.digitalWrite(self.ledB, wiringpi.GPIO.LOW)
110
+ else:
111
+ self.ledR.on()
112
+ self.ledG.on()
113
+ self.ledB.on()