I want to prevent the speaker connected to the Raspberry Pi (jessie) from bouncing when the OS is restarted (Python script)

Preface

This article uses only the script of I want to prevent the speaker connected to Raspberry Pi (jessie) from getting stuck when the OS is restarted (Perl script) It is the content that I wrote it. Therefore, please be aware that there is nothing new except for scripts.

Premise

Please check I want to prevent the speaker connected to the Raspberry Pi (jessie) from becoming bon when the OS is restarted (Perl script).

Commentary

Let's go now.

Whole script

I will paste it for the time being. I will explain it below.

get_dac_port_num.py


#!/usr/bin/python
# coding: utf-8

import sys
import re

HUB = {}

reBUS  = re.compile(r'Bus (\d*)\.Port')
reHUB  = re.compile(r'^(\s*)\|__.*Port (\d*): .*Class=Hub')
rePort = re.compile(r'^(\s*)\|__.*Port (\d*): .*Driver=snd-usb-audio')

for line in sys.stdin:
        tmp = reHUB.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2))) + "."
                continue

        tmp = rePort.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2)))
                for v in range(0,len(tmp.group(1))+1):
                        if HUB.has_key(v):
                                sys.stdout.write(HUB.get(v))
                exit()

        tmp = reBUS.search( line )
        if tmp:
                HUB[0] = str(int(tmp.group(1))) + "-"
                continue

Let's take a closer look.

import

I imported sys and re to use standard input and regular expressions.

import sys
import re

Variable definition

Define a dictionary to hold each number. The name doesn't have to be HUB, but it happened to happen.

HUB = {}

The following is pre-compiled as a spell to turn regular expressions faster. From top to bottom, regular expressions for bus numbers, hub numbers, and port numbers. The regular expression itself is [at Perl](http://qiita.com/kouichirou/items/76dadc7cab6ef694fe18#%E5%AD%90%E3%82%B9%E3%82%AF%E3%83%AA%E3 It is exactly the same as% 83% 97% E3% 83% 88).

reBUS  = re.compile(r'Bus (\d*)\.Port')
reHUB  = re.compile(r'^(\s*)\|__.*Port (\d*): .*Class=Hub')
rePort = re.compile(r'^(\s*)\|__.*Port (\d*): .*Driver=snd-usb-audio')

I won't explain the details, but each group (enclosed in parentheses) for back reference is included. For details, please refer to here.

Main routine

for statement

It means that it will process line by line from the standard input.

for line in sys.stdin:

For the time being, [here](http://webdev.bulkitem.com/python%E3%81%A7%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B%E3% I also considered the method of reading the whole first like buffer = sys.stdin.readline.splitlines () as written around 82% 92% E8% AA% AD% E3% 82% 80). However, it seems that the speed was slow, so I stopped. (Even though, the difference was about 10% when the test data was inflated to about 200,000 lines (which is unlikely with lsusb -t), so either one is OK for practical use.)

Contents of for 1 (HUB)

First, check the value of HUB. Find the read row in the precompiled object reHUB. tmp is the object that contains the search results. It is used to back-reference the value acquired as a group at the time of search as tmp.group (1). If there is an object in the search result (= if the regular expression matches), add a value to the HUB dictionary. As in the example, the key is the number of blank characters at the beginning of the corresponding line, and the value is the number following Port, which is acquired as a character string, converted to int type, and then added again as a character string with "." (Dot).

        tmp = reHUB.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2))) + "."
                continue

For example, the input string is as follows

    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M

If it is, there are 4 digits of space.

HUB[len("    ")] = str(int("1")) + "."

That is, HUB [4] =" 1 "+". ". By the way, the reason why the number is set to int and str is that if the number part is 01, the desired result to finally pass to unbind will be strange, for example, 01-01.01. So I'm in trouble: severe :. Therefore, even if it is the character string 01, if you int it, it will become 1, which is convenient later.

After assigning the value, continue and return to the head of for.

                continue

If you do not include this, it will be very useless because it will search for subsequent rePort and reBUS. The total processing will be almost doubled. Even so, it takes about 1.2 seconds or 0.6 seconds for about 200,000 lines, so ... (Omitted below)

Contents of for 2 (Port)

The processing content is almost the same as the above Hub, but the difference is that there is output processing.

        tmp = rePort.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2)))
                for v in range(0,len(tmp.group(1))+1):
                        if HUB.has_key(v):
                                sys.stdout.write(HUB.get(v))
                exit()

Match in the port search = Both BUS and HUB should already have values. Therefore, the value entered in the HUB dictionary is output as much as necessary. (As much as you need, because if there are long branches with many HUBs hanging in the middle, the HUBs will be as deep as the number of HUBs.

For example, suppose there is a long branch in the middle and the HUB dictionary is in the following state. (Dictionary keys shouldn't be sorted by nature, but for simplicity.)

['0':'1-' , '4':'2.' , '8':'1.' , '12':'3.' , '16':'2.' , '20':'1.' ]
#To value-Is attached to BUS,.HUB is attached.

Then take a few steps

['0':'1-' , '4':'3.' , '8':'3' , '12':'3.' , '16':'2.' , '20':'1.' ]
#To value-Is attached to BUS,.HUB is attached with, and Port is only the number without anything.

In that situation, it is correct to output 1-3.3, but if you output all of them, it will be meaningless as 1-3.33.2.1..

So, for the HUB dictionary key, create a value from 0 for the required number of digits (up to 8 in the above case) with range, but since Python Range starts from 0, you have to +1.

                for v in range(0,len(tmp.group(1))+1):
                        if HUB.has_key(v):
                                sys.stdout.write(HUB.get(v))

Also, since the key takes discrete values, it is checked with has_key to prevent errors when there are no values.

Contents of for 3 (BUS)

Finally, it's BUS. However, it is almost the same as HUB. The difference is that the key is 0, which is a definite point. Since BUS is the highest level, there is no need to calculate it one by one.

        tmp = reBUS.search( line )
        if tmp:
                HUB[0] = str(int(tmp.group(1))) + "-"
                continue

End of explanation

The speedy story of Perl and Python

The result of lsusb -t is at most a dozen lines, so in practice it doesn't matter which one you really use: sweat_smile :, I wonder how different the performance is, as mentioned above, the number of target lines is wasted. I tested it on the same Linux with more cases. It has been inflated to about 200,000 lines, but there is no point in mentioning the number of lines that are left over, so let's just worry about how much the same number of lines makes a difference.

When I measured the time of the Perl script (excerpt of only the corresponding process) several times with time, it was roughly

Perl


real    0m0.450s
user    0m0.433s
sys     0m0.031s

It's a sense of numbers. On the other hand, with Python,

Python


real    0m0.720s
user    0m0.710s
sys     0m0.019s

Feeling like. As for the value of user, Python is about 1.6 times. There is a considerable difference.

When the number of target lines is about a few actual lines

Perl


real    0m0.011s
user    0m0.004s
sys     0m0.006s

Python


real    0m0.021s
user    0m0.012s
sys     0m0.009s

I felt like saying. Hmm. I thought Perl was pretty heavy, but is it a bit faster than Python? (In this process, though.)

Speedy story only in Python

For the time being, I was concerned about the speed, so I thought about various Python algorithms as such.

Insert Continue → It's faster

As I have already explained above, it will be faster to think normally. After processing something, I will go to the next line without any extra processing. By the way, I think it would be better to do this in the Perl version as well, but I didn't want to change what I could write short, so I stopped thinking about it.

Instead of the order of BUS, HUB, Port, the order is HUB, Port, BUS → It became faster

I also tried various things, but

--The number of BUS is absolutely small, so the last one is fine. ――As for HUB, I think it was better to bring it first because many HUBs were intentionally included in the inflated test data this time. ――So Port is in the middle. If there are few HUBs and there are a lot of ports, it may be better to change the order of HUBs and ports.

So I calmed down. If it's a university algorithm class, it would be evaluated by counting the number, but well, it's omitted: stuck_out_tongue :.

Try using the function → It's late

Since the processing in for is similar for BUS, HUB, and Port, I just wanted to make it a function. However, I had to change the regular expression of reBUS to make it a function, and it seems that the new reBUS was a drag, and it was about 10% slower. (In addition, the output part is incomplete because it was omitted in the following source, and it is cute that there is no "-" or "." When substituting into the HUB dictionary. It does not affect so much.)

reBUS  = re.compile(r'^\S*(\s*)Bus (\d*)\.Port')
#reBUS  = re.compile(r'Bus (\d*)\.Port')
reHUB  = re.compile(r'^(\s*)\|__.*Port (\d*): .*Class=Hub')
rePort = re.compile(r'^(\s*)\|__.*Port (\d*): .*Driver=snd-usb-audio')

def calc(re,line):
        tmp = re.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = int(tmp.group(2))
                return True
        else:
                return False

for line in sys.stdin:
        if calc(reHUB,line):
                continue

        if calc(rePort,line):
                print HUB
                exit()

        if calc(reBUS,line):
                continue

I quit the function, but I'll write it simply → It's late

I put the precompiled object in a dictionary called reS and for it. It looks like it looks beautiful, it doesn't look like it. .. The speed has almost doubled. It would be superfluous to check RE == rePort every time after assigning to the new reBUS and reS and the HUB dictionary.

reS = [reBUS , rePort , reHUB ]

for line in sys.stdin:
        for RE in reS:
                tmp = RE.search( line )
                if tmp:
                        HUB[len(tmp.group(1))] = int(tmp.group(2))
                        if RE == rePort:
                                print HUB
                                exit()
                        continue

The whole source again

So, I tried various trials and errors, and it is the following source again. (Same as the first)

get_dac_port_num.py


#!/usr/bin/python
# coding: utf-8

import sys
import re

HUB = {}

reBUS  = re.compile(r'Bus (\d*)\.Port')
reHUB  = re.compile(r'^(\s*)\|__.*Port (\d*): .*Class=Hub')
rePort = re.compile(r'^(\s*)\|__.*Port (\d*): .*Driver=snd-usb-audio')

for line in sys.stdin:
        tmp = reHUB.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2))) + "."
                continue

        tmp = rePort.search( line )
        if tmp:
                HUB[len(tmp.group(1))] = str(int(tmp.group(2)))
                for v in range(0,len(tmp.group(1))+1):
                        if HUB.has_key(v):
                                sys.stdout.write(HUB.get(v))
                exit()

        tmp = reBUS.search( line )
        if tmp:
                HUB[0] = str(int(tmp.group(1))) + "-"
                continue

First Python impression

Recently, I was writing code only in languages such as PHP, Shell, and Perl, so I was a little annoyed by the politeness of Python as rumored. However, on the other hand, there was a recent awareness that I had to do type conversion properly, and that if I abbreviated it to a maniac so much, I wouldn't understand it for beginners, so I pinpointed the spine like when writing Java. I was able to work on it with the feeling (?)

I think I'm still using only the very basic features of Python, so I'll write about it again if I have something interesting to study in the future.

Finally

This Python script is [Child script for Perl](http://qiita.com/kouichirou/items/76dadc7cab6ef694fe18#%E5%AD%90%E3%82%B9%E3%82%AF%E3%83 % AA% E3% 83% 97% E3% 83% 88) does not hit lsusb -t internally, so if you want to implement it, chmod ugo + x [Python script full path] Keep it

/usb/bin/lsusb -t | [Python script full path] > $UNBIND

Please describe in the parent script like.

Then.

Recommended Posts

I want to prevent the speaker connected to the Raspberry Pi (jessie) from bouncing when the OS is restarted (Python script)
I want to run the Python GUI when starting Raspberry Pi
About the error I encountered when trying to use Adafruit_DHT from Python on a Raspberry Pi
I connected the thermo sensor to the Raspberry Pi and measured the temperature (Python)
[Hyperledger Iroha] Query with Python library
I wanted to use the Python library from MATLAB
I tried using the Python library from Ruby with PyCall
About the error I encountered when trying to use Adafruit_DHT from Python on a Raspberry Pi
I created a Python library to call the LINE WORKS API
After researching the Python library, I understood a little about egg.info.
A story I was addicted to when inserting from Python to a PostgreSQL table
I want to prevent the speaker connected to the Raspberry Pi (jessie) from bouncing when the OS is restarted (Python script)
I want to be notified of the connection environment when the Raspberry Pi connects to the network
I want to initialize if the value is empty (python)
I tried changing the python script from 2.7.11 to 3.6.0 on windows10
I want to use jar from python
[Python] I want to know the variables in the function when an error occurs!
I want to be notified when the command operation is completed on linux!
I want to email from Gmail using Python.
[Python] I want to manage 7DaysToDie from Discord! 1/3
I want to use ceres solver from python
What I did when updating from Python 2.6 to 2.7
[Python] I want to manage 7DaysToDie from Discord! 2/3
I want to make C ++ code from Python code!
I want to display the progress in Python!
[Python] I made a system to introduce "recipes I really want" from the recipe site!
When I tried to do socket communication with Raspberry Pi, the protocol was different
How to pass arguments when invoking python script from blender on the command line
From setting up Raspberry Pi to installing Python environment
I want to see the file name from DataLoader
How to use the Raspberry Pi relay module Python
I want to inherit to the back with python dataclass
[Python3] I want to generate harassment names from Japanese!
I want to write in Python! (3) Utilize the mock
I want to use the R dataset in python
I want to do something in Python when I finish
[Selenium] I want to display the browser by hitting the driver on the host OS from WSL
I want to output while converting the value of the type (e.g. datetime) that is not supported when outputting json with python
maya Python I want to fix the baked animation again.
I want to start a lot of processes from python
I want to calculate the allowable downtime from the operating rate
[Python] I want to use the -h option with argparse
I want to disable interrupts on Raspberry Pi (≒ DI / EI)
I want to send a message from Python to LINE Bot
I want to know the features of Python and pip
Change the message displayed when logging in to Raspberry Pi
I sent the data of Raspberry Pi to GCP (free)
Write a script in Shell and Python to notify you in Slack when the process is finished
How to deal with the problem that the current directory moves when Python is executed from Atom
I want to automatically find high-quality parts from the videos I shot
I tried to automate the watering of the planter with Raspberry Pi
[Linux] I want to know the date when the user logged in
I want to output the beginning of the next month with Python
Use python on Raspberry Pi 3 to illuminate the LED (Hello World)
I want to create a system to prevent forgetting to tighten the key 1
A memo when connecting bluetooth from a smartphone / PC to Raspberry Pi 4
What to do when the value type is ambiguous in Python?
[Python] What to do when PEP8 is violated in the process of importing from the directory added to sys.path
I made a pet camera that is always connected with WebRTC (Nuxt.js + Python + Firebase + SkyWay + Raspberry Pi)
I want to display the number of num_boost_rounds when early_stopping is applied using XGBoost callback (not achieved)
Read the data of the NFC reader connected to Raspberry Pi 3 with Python and send it to openFrameworks with OSC