LCDManager- fault protection

Imagine situation, you have a perfect LCD that displays a perfect content on a perfect day. On this perfect day some imperfect being trip and unplug power from a display. It goes off, RPi tries to send packet to it and a program explodes with:


IOError: [Errno 5] Input/output error

And the perfect day is back to a typical day. What can we do about it ? We may write a fault protection.
During usage I met mostly with two problems: one power was lost and second there were a some kind of interference and screen goes wild. How wild ? With each tick content was shifted or a gibberish was displayed. We can do something with both cases.

Download source from Bitbucket

Where to protect

Where to implement such protection? Definitely not in driver, so we have: LCDManager or CharLCD. I think we should go with LCDManager. CharLCD should stay clean and allow developer to do as they want with errors.  But another question is: manager or display server ? My bet is on manager.

Seems easy but first problem is with virtual lcds. They may have more than one physical screen. What should happen if only one screen fails? Manger have no idea what is below it. So it can intercept all or none lcd’s communication faults.

Power loss or other communication interruptions

Power loss to screen should not crash software.  RPi may run on additional battery and it’s job is to gather data from sensors, saving it and additionally displaying something on screen. Displaying is not a primary task so failing to do so shouldn’t crash program.
First we need to catch an exception that is thrown when RPi can’t communicate with screen. We are looking for IOError exception. Just wrap self.lcd.flush() call in flush function:

def flush(self):
    """display content"""
    try:
        self.lcd.flush()
    except IOError:
        pass

But this is the beginning. After power is back screen is not initialized and wont work. But in each class from CharLCD exist an init() function and self.initialized variable.  We will use them.
After error is caught we will reset initialized. And first line in flush will check if lcd is initialized and if not we will try to do so.  New flush():


    def flush(self):
        """display content"""
        try:
            if not self.lcd.initialized:
                self.lcd.init()
            self.lcd.flush()
        except IOError:
            self.lcd.initialized = False

And that’s all 🙂

Interference

This problem is much harder to detect. It happens when something interference with communication with lcd. The result may be a gibberish on screen or it may activate some functions like shifting.

We could read content from screen and compare it with buffer but remember that HD44780 operates at 5V. Sending 5V to RPi via GPIO will harm it. That is why we put lcd in write only state.

There is something we can do, we may reinitialize screen periodically. Once per 5 minutes should be enough.

Add options dictionary to __init__:

self.options = {
    'refresh_after': 60 * 5,  # 5 minutes
    'last_refresh': time.time()
}

New function:

def _time_to_refresh(self):
    """force lcd reinitializtion after required time"""
    if self.options['last_refresh'] + self.options['refresh_after'] < time.time():
        self.options['last_refresh'] = time.time()
        self.lcd.initialized = False

and put

self._time_to_refresh()

as first line in flush function.

Summary

LCDManager received two nice features, one is ability to restart lcd after communication loss and second is forcing lcd to refresh after 5 minute to clean any gibberish.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s