打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Hardware/Peripheral Device Design Pattern
Hardware Device Design Pattern
We have already looked at classes that provide a high level interface to theunderlying hardware (e.g.Serial Port).Here we will look at the design of classes corresponding to the individualdevices. The main objective is to keep all register programming information atone place.
Intent
The Hardware Device Design Pattern encapsulates the actual hardware devicebeing programmed. The main idea is to encapsulate device register programmingand bit manipulation into a single class dealing with the device.
Also Known As
Device
Hardware Interface
Peripheral Interface
Peripheral
Motivation
Very often the lowest level of code that interfaces with the hardware isdifficult to understand and maintain. One of the main reasons for this is the idiosyncrasiesof register level programming model of hardware devices.  Very oftendevices require registers to be accessed in a certain sequence. Defining a classto represent the device can go a long way in simplifying the code by decouplingthe low level code and register manipulation.
Another motivation for this design pattern is skill sets. Often details aboutintricacies of register programming in devices are understood only by thepersons familiar with the hardware design. Many times other low level code mightbe written by software engineers with just basic understanding of hardware.
Also note that separating the device programming and logic simplifies portingof the code to a different hardware platform.
Applicability
This pattern can be used to represent any hardware device.
Structure
The structure of class in this design pattern largely depends upon theregister programming model of the device being programmed. In most cases, thisdesign pattern would be implemented as a single class representing the device.In case of complex devices, the device might be modeled as a main device classand other subclasses modeling different parts of the device.
Participants
This design pattern generally interfaces with other classes that need toaccess hardware registers.
Collaboration
Collaboration between the device class and other classes would largely dependupon the purpose for which the device is being used. For example, a hardwaredevice that provides timers, serial ports and a DMA controller might be modeledjust as a serial device if other device functionality is not being used.
Consequences
The device involved in low level hardware programming is simplified asdetails about register manipulation have been hidden within the class. Thus thecode accessing the hardware device can focus on the logic of the operation beingperformed. As noted earlier, porting of hardware dependent software is alsosimplified.
Implementation
We will study the implementation of this pattern by working with an imaginaryserial device with the following register set:
Status Register (STAT): This read only register contains the following status bits: Bit 0: Transmit Buffer Has Empty Space
Bit 1: Receive Buffer Has Data
Bit 2: Transmit under run
Bit 3: Receive overrun
Action Register (ACT): Bits in this write only register correspond to the bits in the status register. A condition in the status register can be cleared by writing the corresponding bit as 1. Note that bit 0 automatically gets cleared when writes are performed to the transmit buffer. Bit 1 is cleared automatically when reads are performed from the receive buffer. Bit 2 and 3 however need to be cleared explicitly.
Transmit Buffer (TXBUF): Write only buffer in which bytes meant for transmission should be written.
Receive Buffer (RXBUF): Read only buffer in which received bytes are stored.
Sample Code and Usage
Here is the code for the Serial_Device class:
Serial_Device
class Serial_Device { enum Register_Offsets { STAT_REG_OFFSET = 0, ACT_REG_OFFSET = 0, TXBUF_OFFSET = 1, RXBUF_OFFSET = 2 }; enum Status_Register_Bits { TX_EMPTY, RX_DATA, TX_UNDERRUN, RX_OVERRUN }; const long m_status_Register; const long m_action_Register; const long m_transmit_Register; const long m_receive_Register; public: Serial_Device(long baseAddress) : m_status_Register(baseAddress + STAT_REG_OFFSET), m_action_Register(baseAddress + ACT_REG_OFFSET), m_transmit_Register(baseAddress + TXBUF_OFFSET), m_receive_Register(baseAddress + RXBUF_OFFSET) { } // Use this method to determine if a transmit interrupt might be // pending. bool Transmitter_Has_Space() const { return ((io_read(m_status_Register) & TX_EMPTY) == TX_EMPTY); } // This method returns true if a receive interrupt is pending bool Receiver_Has_Data() const { return ((io_read(m_status_Register) & RX_DATA) == RX_DATA); } // Returns true if transmit error interrupt is active bool Transmitter_Has_Error() const { return ((io_read(m_status_Register) & TX_UNDERRUN) == TX_UNDERRUN); } // Returns true if receive error interrupt is active bool Receiver_Has_Error() const { return ((io_read(m_status_Register) & RX_OVERRUN) == RX_OVERRUN); } // Clear all the error conditions void Clear_Errors() const { io_write(m_action_Register, TX_UNDERRUN | TX_OVERRUN); } // Write_Data transmits the specified number of bytes. All bytes // may not be transmitted due to transmit buffer space. The total // number of transmitted bytes is returned. int Write_Data(const char *pData, int byteCount) const { // Keep writing transmit bytes until all the bytes // have been transmitted or transmit buffer has no space for (int txCount=0; i < byteCount; txCount++) { if (!Transmitter_Has_Space()) { break; } // Write the byte to the transmit buffer for transmission io_write(m_transmit_Register, pData[txCount]); } // Return the count of transmitted bytes return txCount; } // Read_Data reads the bytes from the device. The maximum number // of bytes to be read can be specified. The actual number // of received bytes is returned. int Read_Data(char *pData, int byteLimit) const { // Keep reading received bytes until all the received bytes // have been copied or specified limit has been reached for (int rxCount=0; i < byteLimit; rxCount++) { if (!Receiver_Has_Data()) { break; } pData[rxCount] = io_read(m_receive_Register); } // Return count of received bytes return rxCount; } };
Known Uses
This pattern is used to decouple the logical device handling and deviceregister manipulation.
Related Patterns
Serial Port Design Pattern
High Speed Serial Port Design Pattern
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Combining C’s volatile and const Keywords ? Barr Code
GUI显示系统之SurfaceFlinger
Android6.0 显示系统(四) 图像显示相关
嵌入式编程中的复杂指针的使用
SurfaceFlinger, Frame buffer device, Overlays...
i2cToolsDocumentation – lm
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服