2014-09-16 1 views
0

특정 통신 인터페이스를 통해 액세스 할 수있는 하드웨어를 처리하는 코드를 작성하고 있습니다. 전체 장치를 설명하는 개체의 속성으로 특정 레지스터 집합을 정의하고 싶습니다. 하드웨어에 액세스 할 수있는 hw_read(address, size)hw_write(address, size, array_of_values) 기능이 있다고 가정합니다.파이썬 - 하드웨어 처리, 하드웨어 레지스터를 객체의 속성으로 효율적으로 구현하는 방법

주소 10에서 시작하여 길이가 2 인 레지스터 블록이 있으며이를 "reg1"속성에 할당하려고한다고 가정 해 보겠습니다. 나는 다음과 같은 방법으로 작업을 수행 할 수 있습니다

class my_hardware(object): 
    def __init__(self): 
    # Perform initialization 
    return 
    @property 
    def reg1(self): 
     return hw_read(10,2) 
    @reg1.setter 
    def reg1(self,value): 
     hw_write(10,2,value) 

위의 구현은 매우 편리하지 않습니다, 나는 두 번 주소와 크기를 제공해야한다. 특히 많은 수의 레지스터를 정의해야하는 경우 오류가 발생하기 쉽습니다.

dev1.reg1=(0x1234,0x3211) 
print dev1.reg2 

두 번째 방법도 있습니다 통해에 액세스 한 후

dev1=my_hardware() 
dev1.define_register("reg1",10,2) 
dev1.define_register("reg2",12,6) 

그리고 : 내가 쉽게 은 아래와 같은 몇 가지 레지스터를 설정 정의 할 수 있음을, 같은 방법으로 그것을 구현하는 것이 가능 중요한 장점은 외부 텍스트 파일 (예 : VHDL 합성에도 사용됨)에서 레지스터 목록 (이름, 주소 및 크기)을 읽을 수 있다는 것입니다.

업데이트 가능한 솔루션?

>>> a=my_hardware() 
>>> a.add_reg("reg1",10,2) 
>>> a.add_reg("reg2",20,3) 
>>> a.reg1 
read:10, 2 
(4660, 4660) 
>>> a.reg2 
read:20, 3 
(4660, 4660, 4660) 
>>> a.reg1=(10, 11) 
write:10, 2 val=(10, 11) 
>>> a.reg2=(10, 11, 12) 
write:20, 3 val=(10, 11, 12) 
: 더미 hw_read 및 hw_write 기능

def hw_write (first,size,val): 
    print "write:"+str(first)+", "+str(size)+" val="+str(val) 

def hw_read (first,size): 
    print "read:"+str(first)+", "+str(size) 
    return (0x1234,)*size 

class my_hardware(object): 
    def __init__(self): 
     return 
    def add_reg(self,name,first,size): 
     setattr(my_hardware,name,property(lambda self : hw_read(first,size), lambda self, x: hw_write(first,size,x))) 
이하

있는 샘플 결과 :

성질 추가 동적 관련된 SOE 소식을 연구 한 결과, I는 다음과 같이 코드로 필요한 기능을 달성

위의 해결 방법이 합리적인지 여부를 알려 주시면 감사하겠습니다.

내가 볼 수있는 한 가지 문제점 (또는 특징)은 레지스터가 "클래스 당", "인스턴스별로"정의되어 있지 않다는 것입니다. 동일한 레지스터 세트를 가진 몇 개의 디바이스가있는 경우, 하지만, "my_hardware"클래스를 사용하여 동일한 버스에 연결된 서로 다른 레지스터 세트를 가진 다른 디바이스에 액세스하려는 경우 오해의 소지가있을 수 있습니다.

I 유도 클래스가 특정 장치를 설명 정의하고 클래스 당 레지스터를 정의 할 수있는 용액, 발견 2

업데이트 : 이하

def hw_write (first,size,val): 
    print "write:"+str(first)+", "+str(size)+"val="+str(val) 

def hw_read (first,size): 
    print "read:"+str(first)+", "+str(size) 
    return (0x1234,)*size 

class my_hardware(object): 
    def __init__(self, base_address): 
     self.ba = base_address 
     return 
    @classmethod 
    def add_reg(myclass,name,first,size): 
     setattr(myclass,name,property(lambda self : hw_read(self.ba+first,size), lambda self, x: hw_write(self.ba+first,size,x))) 

가 정확한 동작을 보여주는 샘플 세션이다 :

>>> class dev1(my_hardware): 
... pass 
... 
>>> class dev2(my_hardware): 
... pass 
... 
>>> dev1.add_reg("reg1",10,2) 
>>> dev2.add_reg("reg2",15,3) 
>>> a=dev1(100) 
>>> b=dev2(200) 
>>> a.reg1 
read:110, 2 
(4660, 4660) 
>>> a.reg2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'dev1' object has no attribute 'reg2' 
>>> b.reg1 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'dev2' object has no attribute 'reg1' 
>>> b.reg2 
read:215, 3 
(4660, 4660, 4660) 

자세히 알 수 있듯이 레지스터 reg1은 클래스 "dev1"의 장치에 정의되어 있습니다. w hile 레지스터 reg2는 dev2 클래스의 장치에 정의됩니다. 물론이 경우에는 각 장치에 전달할 기본 주소가 필요하므로 "base_address"를 생성자에 추가해야했습니다.

덕분에, 보이 테크

+0

관련 항목 : http://stackoverflow.com/questions/1325673/how-to-add-property-to-a-python-class-dynamically –

답변

1

업데이트 (약간의 변경 사항이 두 번째 솔루션의 기능에 맞게) : 당신은 기술자 프로토콜 (https://docs.python.org/3.4/howto/descriptor.html)를 사용하여 작은 도메인 특정 언어 (http://en.wikipedia.org/wiki/Domain-specific_language)를 구현할 수있다. 예를 들어, 설명자가 주어진 경우 :

이 설명자를 사용하면 클래스를 작성하고 레지스터를 의미 론적으로 나타낼 수 있습니다. 또, 예를 들면 :

class AddressableHardware(object): 
    """ 
    Base class for addressable hardware components. 

    Attributes: 
    base_address -- the base address of the device. 
    """ 

    def __init__(self, base_address): 
     self.base_address = base_address 

class MyHardware(AddressableHardware): 
    """ 
    An example hardware device. 
    """ 

    reg1 = RegisterDescriptor(2, 4) 
    reg2 = RegisterDescriptor(6, 1) 

    def __init__(self, base_address): 
     AddressableHardware.__init__(self, base_address) 

mh = MyHardware(0x2E) 
print(mh.reg1) 
mh.reg2 = b'\x00' 

업데이트 : 나는 어쩌면 일부 장치의 각 유형은 자신의 클래스 및 관련 방법을 것보다 선언적인 접근 방식을, (촬영했습니다으로 이러한 접근 방식은 두 번째 솔루션 다르다 장치에 대한 하위 수준의 액세스를 숨기는 도우미 메서드)를 사용하고 더 많은 Pythonic 데이터 유형을 처리합니다. 위의 설명 솔루션을 사용하면 같은 끝낼 것 :

class HardwareDeviceA(AddressableHardware): 
    reg1 = RegisterDescriptor(10, 2) 
    reg2 = RegisterDescriptor(20, 3) 

    def __init__(self, base_address): 
     AddressableHardware.__init__(self, base_address) 

class HardwareDeviceB(AddressableHardware): 
    reg1 = RegisterDescriptor(10, 4) 

    def __init__(self, base_address): 
     AddressableHardware.__init__(self, base_address) 

이 서로 다른 기본 주소에서 컴퓨터에 연결된 장치 유형 A와 B의 여러 인스턴스를 가질 수 있습니다, 당신은 할 필요가 없습니다 매번 레지스터를 설정하십시오.

+0

브렛, 내 솔루션은 내 솔루션에 해당하는지, 두 번째 업데이트에 설명되어 있거나 어쩌면 더 좋을 수도 있습니다. 귀하의 솔루션에서 setattr을 사용하여 동적으로 필드 이름을 생성 할 수 있다는 것을 알고 있습니다. – wzab

+0

죄송합니다. 통역사에게 잘못된 버전의 솔루션을 복사했습니다. 어쨌든 필자는 선언적 접근 방식이 더 명확하다는 것을 생각한다. 레지스터를 사용할 수있는 클래스를 작성할 때 보장 할 것이므로 클래스의 인스턴스 메서드로 장치 관련 기능을 배치해야한다. –

관련 문제