勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧事件驅動‧三上

雖說用『裝置樹』 Device Tree 來描述硬體的介接,提供充分的相關資訊 ,因此作業系統可以選取『適當對應』裝置驅動程式。聽起來如是美好,易懂易解,然而實務上卻常叫人一頭霧水,這又是怎麼一回事的呢?

這或許因為人們不知道『困難』的問題有兩大類,一類的問題了解很『容易』,但是幾乎沒人會,這叫做『真難』。比方說︰
證明『費馬大定理

x^n + y^n= z^n \ , n \geq \ 3

沒有整數解。即使這個定理已被證明,想要『讀懂』依然十分困難 !這一類的『問題』在『實務』並上不多見,或許由於反正難有人能『解讀』的吧!!

另一類的問題對於『學習者』而言,就需要特別的『注意』。它的每一『小部份』也許都『不困難』,然而有太多的部份『構成』,十分的『複雜』。如果缺乏『系統思維』,又對於『容易理解』之『小部份』不能『深化認識』建立自身『體系』,以至於『引發』了常見的『或知或解』與『或不知或不解』現象,這大概也不奇怪的哩!?舉例來講,因為 Kernel 4.1.4 之更新,作者不得不『驗證』自己文本所說到底還『正不正確』?所以想著有沒有『比較快速』的辦法呢??針對 GPIO 的『測試』而言,想起了曾經編寫的

M♪o 之學習筆記本《巳》文章︰【䷜】樽酒簋貳》之

【TuxIOme V0.1】。設想那 M♪o 學習時所用的學習板

P1070822

 

有四十根針而且含括多種 GPIO ,又是自己寫的,豈不正是合適︰

行 習 行習︰以及 TuxIOme V0.1 版,參考原始碼︰

 

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import math
import operator
import string
import threading
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

開 = 亮 = 低 = 0
關 = 滅 = 高 = 1

from time import sleep
 
import tpg

if tpg.__python__ == 3:
    operator.div = operator.truediv
    raw_input = input

def make_op(op):
    return {
        '加'   : operator.add,
        '減'   : operator.sub,
        '乘'   : operator.mul,
        '除'   : operator.div,
        '剩'   : operator.mod,
        '^'   : lambda x,y:x**y,
        '**'  : lambda x,y:x**y,
        '餘弦' : math.cos,
        '正弦' : math.sin,
        '切弦' : math.tan,
        'acos': math.acos,
        'asin': math.asin,
        'atan': math.atan,
        '平方' : lambda x:x*x,
        '根號': math.sqrt,
        '正值' : abs,
        'norm': lambda x,y:math.sqrt(x*x+y*y),
    }[op]

數碼賦值 = [(滅, 亮, 亮, 滅, 滅, 滅, 亮, 滅), (滅, 滅, 滅, 滅, 亮, 亮, 亮, 滅), (滅, 亮, 亮, 滅, 滅, 滅, 亮, 滅),   (滅, 滅, 滅, 滅, 亮, 亮, 亮, 滅)
]

遲延 = 0.012

# 數碼管

四位數碼管位選一 = 17
四位數碼管位選二 = 27
四位數碼管位選三 = 22
四位數碼管位選四 = 10

LEDA = 21
LEDB = 16
LEDC = 19
LEDD = 6
LEDE = 5
LEDF = 20
LEDG = 26
LEDH = 13

# 初始態

GPIO.setup(四位數碼管位選一, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選二, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選三, GPIO.OUT, initial=關)
GPIO.setup(四位數碼管位選四, GPIO.OUT, initial=關)

GPIO.setup(LEDA, GPIO.OUT, initial=滅)
GPIO.setup(LEDB, GPIO.OUT, initial=滅)
GPIO.setup(LEDC, GPIO.OUT, initial=滅)
GPIO.setup(LEDD, GPIO.OUT, initial=滅)
GPIO.setup(LEDE, GPIO.OUT, initial=滅)
GPIO.setup(LEDF, GPIO.OUT, initial=滅)
GPIO.setup(LEDG, GPIO.OUT, initial=滅)
GPIO.setup(LEDH, GPIO.OUT, initial=滅)



def 數碼管執行緒():
    global 數碼賦值
    global 遲延

    數碼管 = [LEDA, LEDB, LEDC, LEDD, LEDE, LEDF, LEDG, LEDH]

    while True :

        for 單元 in range(0,4):
            if 單元 == 0 :
                GPIO.output(四位數碼管位選一, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選一, 關)

            if 單元 == 1 :
                GPIO.output(四位數碼管位選二, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選二, 關)

            if 單元 == 2 :
                GPIO.output(四位數碼管位選三, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選三, 關)

            if 單元 == 3 :
                GPIO.output(四位數碼管位選四, 開)
                GPIO.output(數碼管, 數碼賦值[單元])
                sleep(0.002)
                GPIO.output(四位數碼管位選四, 關)

        sleep(遲延)

數碼緒 = threading.Thread(name="數碼", target=數碼管執行緒)
數碼緒.daemon = True
數碼緒.start()

數碼管輸出字典 = { "0" : (亮, 亮, 亮, 亮, 亮, 亮, 滅, 滅) ,
                   "1" : (滅, 亮, 亮, 滅, 滅, 滅, 滅, 滅) ,
                   "2" : (亮, 亮, 滅, 亮, 亮, 滅, 亮, 滅) ,
                   "3" : (亮, 亮, 亮, 亮, 滅, 滅, 亮, 滅) ,
                   "4" : (滅, 亮, 亮, 滅, 滅, 亮, 亮, 滅) ,
                   "5" : (亮, 滅, 亮, 亮, 滅, 亮, 亮, 滅) ,
                   "6" : (亮, 滅, 亮, 亮, 亮, 亮, 亮, 滅) ,
                   "7" : (亮, 亮, 亮, 滅, 滅, 滅, 滅, 滅) ,
                   "8" : (亮, 亮, 亮, 亮, 亮, 亮, 亮, 滅) ,
                   "9" : (亮, 亮, 亮, 亮, 滅, 亮, 亮, 滅) ,
                 }


def 輸出數碼管(數據) :
    global 數碼賦值
    global 數碼管輸出字典

    if 數據 > 999.9 :
        return "數值超過 999.9"
    else:

        字符串 = "%05.1f" %數據

        for 單元 in range(0,5):
            if 單元 == 0 :
                數碼賦值[單元] = 數碼管輸出字典[字符串[單元]]
            elif 單元 == 1 :
                數碼賦值[單元] = 數碼管輸出字典[字符串[單元]]
            elif 單元 == 2 :
                暫列 = list(數碼管輸出字典[字符串[單元]])
                暫列[7] = 亮
                數碼賦值[單元] = tuple(暫列)
            elif 單元 == 3 :
                continue
            else:
                數碼賦值[單元 - 1] = 數碼管輸出字典[字符串[單元]]

    return "完成"



GPIO.setup(11, GPIO.OUT, initial=GPIO.HIGH)
小哨子 = GPIO.PWM(11, 130.8)

def 啟動蜂鳴器():
        小哨子.start(100)
        return "蜂鳴器已啟動"

def 響聲控制(頻率):
        小哨子.ChangeFrequency(頻率)
        小哨子.start(50)
        return 頻率

def 噤聲控制(頻率):
        小哨子.ChangeFrequency(頻率)
        小哨子.start(100)
        return "噤聲"

def 控制蜂鳴器(op):
    return {
        '響聲'   : 響聲控制,
        '禁音'   : 噤聲控制,
   }[op]

def 輸入符碼(針碼):
        return GPIO.input(針碼)


def 輸出符碼(針碼, 賦值):
        GPIO.output(針碼, 賦值)
        return "輸出" + str(賦值)

def 出入定義(針碼, 入出):
        if 入出 == "出" :
            GPIO.setup(針碼, GPIO.OUT, initial = GPIO.HIGH)
        else:
            GPIO.setup(針碼, GPIO.IN, pull_up_down = GPIO.PUD_UP)
        return "定義完成"

def 出針定義(針碼):
    GPIO.setup(針碼, GPIO.OUT, initial = GPIO.HIGH)
    return "定義輸出完成"

def 入針定義(針碼):
    GPIO.setup(針碼, GPIO.IN, pull_up_down = GPIO.PUD_UP)
    return "定義輸入完成"


def 入出針定義(op):
    return {
        '入針'   : 入針定義,
        '出針'   : 出針定義,
   }[op]

import subprocess

重複次數 = 1

def 紅外線輸出(字碼):
    global 重複次數
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', 字碼,"--count=" +str(重複次數) ])
    return "已送出"

傳送重複 = 3

訊息編碼表 = {"0" : "KEY_0", "1" : "KEY_1", "2" : "KEY_2", "3" : "KEY_3", "4" : "KEY_4",
              "5" : "KEY_5", "6" : "KEY_6", "7" : "KEY_7", "8" : "KEY_8", "9" : "KEY_9",
             }

訊息解碼表 = {"0" : "0", "1" : "1", "2" : "2", "3" : "3", "4" : "4",
              "5" : "5", "6" : "6", "7" : "7", "8" : "8", "9" : "9",
              "SETUP" : "S", "ENTER" : "-", "BACK" : "E",
             }

def 紅外線發訊(四位數):
    global 傳送重複
    訊息串 = str(四位數)
    if len(訊息串) != 4 :
        return "訊息必須四位數"
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_SETUP","--count=" +str(傳送重複) ])
    for 字碼 in 訊息串 :
        subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', 訊息編碼表[字碼],"--count=" +str(傳送重複) ])
        subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_ENTER","--count=" +str(傳送重複) ])
    subprocess.call(['irsend', 'SEND_ONCE', 'tuxiome', "KEY_BACK","--count=" +str(傳送重複) ])
    return "已發訊"


import lirc
sockid = lirc.init("TuxIOme", blocking=False)

def 紅外線輸入():

    return lirc.nextcode()

def 紅外線收訊():
    空碼 = 0
    狀態 = 0
    字串 = ""
    while True:
        字碼 = 紅外線輸入()
        if 字碼 == [] :
            空碼 += 1
            if 空碼 < 10 :
                continue
            else:
                狀態 = 1
                break

        空碼 = 0
        字串 = 字串 + 訊息解碼表[字碼[0]]

    if 狀態 == 1 :
        return 字串
    else:
        return "錯誤"


def 讀取系統溫度():
    t = subprocess.check_output(['vcgencmd', 'measure_temp'])
    T = t.decode('utf-8')
    Tb = T.find('=')
    Te = T.find("'")
    return float(T[Tb + 1 : Te])

from w1thermsensor import W1ThermSensor
sensor = W1ThermSensor()

def 讀取環境溫度():
    return sensor.get_temperature()

import random

class 實習機板(tpg.Parser, dict):
    r"""
    此為實習基板入出針語言 TuxIOme 0.1,自 Calc.py 擴充而來。由於使用中文之故,
    不能使用預設的 NamedGroupLexer 。
    文法定義如下 ::

        set lexer = CacheLexer

        separator space '\s+' ;

        token 指數運算    '\^|\*\*'                                               make_op         token 入出設定    '(入針|出針)\b' 入出針定義
        token 聲音控制    '(響聲|禁音)\b'                                                   控制蜂鳴器         token 加減運算    '[加|減]' make_op
        token 乘除運算    '[乘|除|剩]'                                                 make_op         token 函數一    '(餘弦|正弦|切弦|acos|asin|atan|平方|根號|正值)\b' make_op
        token 函數二    '(norm)\b'                                              make_op         token real      '(\d+\.\d*|\d*\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+' float
        token integer   '\d+'                                                   int         token VarId     '\w*'                                                    ;          START/e ->                 '變元' e=self.記憶()
            |   VarId/v '=' Expr/e      self[v]=e             |   Expr/e #            |   '定義' Expr/p '出' e=出入定義(p, '出')
#            |   '定義' Expr/p '入'             e=出入定義(p, '入')             |   '入出針'  Expr/p 入出設定/op e=op(p)
            |   '讀入' Expr/p                  e=輸入符碼(p)             |   '寫出' Expr/p '開' e=輸出符碼(p, 0)
            |   '寫出' Expr/p '關'                 e=輸出符碼(p, 1)             |   "打開蜂鳴器" e=啟動蜂鳴器()
            |   "蜂鳴器" 聲音控制/op Expr/p       e = op(p)             |   "顯示" Expr/p e = 輸出數碼管(p)
            |   "IRTX" VarId/s                    e = 紅外線輸出(s)             |   "IRRX" e = 紅外線輸入()
            |   "系統溫度"                        self["CPU溫度"] = e = 讀取系統溫度()             |   "環境溫度" self["周遭溫度"] = e = 讀取環境溫度()
            |   "發訊" Expr/p                     e = 紅外線發訊(p)             |   "收訊" e = 紅外線收訊()
        ;

        Var/self.get(v,0) -> VarId/v ;

        Expr/e -> Term/e ( 加減運算/op Term/t     e=op(e,t)                          )*         ;         Term/t -> Fact/t ( 乘除運算/op Fact/f t=op(t,f)
                         )*
        ;

        Fact/f ->
                加減運算/op Fact/f                f=op(0,f)             |   Pow/f         ;          Pow/f -> Atom/f ( 指數運算/op Fact/e f=op(f,e)
                        )?
        ;

        Atom/a ->
                real/a
            |   integer/a
            |   Function/a
            |   Var/a
            |   '' Expr/a ''
            |   Random/a
        ;

        Function/y ->
                函數一/f '' Expr/x ''               y = f(x)             |   函數二/f '<img src="http://www.freesandal.org/wp-content/ql-cache/quicklatex.com-5618a7a7b23dfd84e41ef622fed8142e_l3.png" class="ql-img-inline-formula quicklatex-auto-format" alt="' Expr/x1 ',' Expr/x2 '" title="Rendered by QuickLaTeX.com" height="19" width="165" style="vertical-align: -5px;"/>' y = f(x1,x2)
        ;

        Random/x -> "四位亂數"                          x = random.randint(0, 9999)         ;      """      def __init__(self):         super().__init__()         self.名稱 = "實習機板"         self["一藍"] = 5         self["二藍"] = 6         self["三藍"] = 13         self["四藍"] = 19         self["五綠"] = 0         self["六綠"] = 1         self["七黃"] = 7         self["八紅"] = 8         self["按鍵一"] = 23         self["按鍵二"] = 18         self["撥碼一"] = 24         self["撥碼二"] = 25        def 記憶(self):         vars = sorted(self.items())         memory = [ "%s = %s"%(var, val) for (var, val) in vars ]         return "\n\t" + "\n\t".join(memory)    print("Calc (TPG example)") 實習機 = 實習機板() while 1:     try:        l = raw_input("\n:")     except UnicodeDecodeError:        continue       if l:         try:             print(實習機(l))         except Exception:             print(tpg.exc())     else:         break   # 數碼緒._stop()  GPIO.cleanup()  </pre>    初步測試如下︰ <pre class="lang:python decode:true ">pi@raspberrypi ~ sudo ./TuxIOme 
Calc (TPG example)

:系統溫度
50.8

:環境溫度
36.875

:變元

	CPU溫度 = 50.8
	一藍 = 5
	七黃 = 7
	三藍 = 13
	二藍 = 6
	五綠 = 0
	八紅 = 8
	六綠 = 1
	周遭溫度 = 36.875
	四藍 = 19
	按鍵一 = 23
	按鍵二 = 18
	撥碼一 = 24
	撥碼二 = 25

:顯示 CPU溫度
完成

:顯示 周遭溫度
完成

:四位亂數
6398

:四位亂數 
5724

:發訊 5200
已發訊

:收訊
S55--22--0-E

:發訊 1314
已發訊

:收訊
S11--33--11--4-EE

:

 

只不過光為了跑那個程式,也得『重讀』自己寫的

M♪o 之學習筆記本《辰》組元︰【䷫】以杞包瓜

M♪o 之學習筆記本《巳》文章︰【䷗】中行獨復

M♪o 之學習筆記本《巳》文章︰【䷊】包荒馮河

M♪o 之學習筆記本《巳》文章︰【䷒】知臨之宜

那些文本 ,然後『再驗』之以相同的測試

 

pi@raspberrypi ~ $ sudo ./TuxIOme 
Calc (TPG example)

:系統溫度
53.0

:環境溫度
36.375

:變元

	CPU溫度 = 53.0
	一藍 = 5
	七黃 = 7
	三藍 = 13
	二藍 = 6
	五綠 = 0
	八紅 = 8
	六綠 = 1
	周遭溫度 = 36.375
	四藍 = 19
	按鍵一 = 23
	按鍵二 = 18
	撥碼一 = 24
	撥碼二 = 25

:顯示 CPU溫度
完成

:顯示 周遭溫度
完成

:四位亂數
7721

:四位亂數 
5104

:發訊 5200
已發訊

:收訊
S55--22--0-00--EE

:發訊 1314
已發訊

:收訊
S1-3-11-4--EE

:

 

豈不是好笑的耶??!!