title: Non blocking serial readline when using PyGame
body: <p>I'm working on a heart rate monitor written in PyGame using an Arduino as an input, the idea being that the game allows you to try and control your heart rate through relaxation exercises regardless of what's on screen.</p>
  
  <p>I want to be able to run things like video/mouse/keybord button capture etc. in the game itself, whilst displaying the heart rate in the top left hand corner and updating it from the arduino when it changes.</p>
  
  <p>The arduino reads a heart rate monitor and then publishes a JSON string formatted as follows:</p>
  
  <pre><code>{'heart_rate': 65,'state': 'running'}
  </code></pre>
  
  <p>"State" can be one of 'intialising','running','failed' or 'stopped'.</p>
  
  <p>Whilst I'm more than familiar with Python, I've taken code from <a href="http://www.akeric.com/blog/?p=1237" rel="nofollow">http://www.akeric.com/blog/?p=1237</a> to get me started with PyGame as I've not ventured here much before.</p>
  
  <p>The problem I have is that when I try and read from the serial port, it locks up the game.</p>
  
  <p>I've read around threading and I think I've implemented it properly, however the following code still blocks:</p>
  
  <pre><code>"""
  default.py
  www.akeric.com - 2010-09-07
  Default, base, initial setup for a pygame program.
  In this case, black background, white circle follows mouse position, and
  framerate is shown in the title-bar.
  """
  
  #-------------------------------------------------------------------------------
  # Imports &amp; Inits
  import sys
  import serial
  import json
  import threading
  
  import pygame
  from pygame.locals import *
  pygame.init()
  ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0)
  
  
  #-------------------------------------------------------------------------------
  # Constants
  VERSION = '1.0'
  WIDTH = 800
  HEIGHT = 600
  FRAMERATE = 60
  CURRENT_MESSAGE = {'heart_rate': 0}
  
  #-------------------------------------------------------------------------------
  # Screen Setup
  screen = pygame.display.set_mode((WIDTH, HEIGHT))
  bgCol = Color('black')
  clock = pygame.time.Clock()
  moduleName = __file__.split('\\')[-1]
  
  #-------------------------------------------------------------------------------
  # Define helper functions, classes, etc...
  def text_objects(text, font):
      textSurface = font.render(text, True, (255,255,255))
      return textSurface, textSurface.get_rect()
  
  def message_display(text,x_pos=(WIDTH/2),y_pos=(HEIGHT/2)):
      largeText = pygame.font.Font('freesansbold.ttf',25)
      TextSurf, TextRect = text_objects(text, largeText)
      TextRect.center = (x_pos,y_pos)
      screen.blit(TextSurf, TextRect)
  
  def spam():
      pos = pygame.mouse.get_pos()
      pygame.draw.circle(screen, Color('white'), pos, 32)
  
  def handle_data(data):
      CURRENT_MESSAGE = json.loads(data)
      message_display("HR: %s" % CURRENT_MESSAGE['heart_rate'],50,20)
  
  def read_from_port(ser):
          while True:
             reading = ser.readline().decode()
             if len(reading) &gt; 0:
                 print "Data Recieved"
                 handle_data(reading)
  
  
  
  #-------------------------------------------------------------------------------
  # Main Program
  def main():
      print "Running Python version: %s"%sys.version
      print "Running PyGame version: %s"%pygame.ver
      print "Running %s version: %s"%(moduleName, VERSION)
      looping = True
  
      # Main Loop-----------------------
      while looping:
          # Maintain our framerate, set caption, clear background:
          clock.tick(FRAMERATE)
          pygame.display.set_caption("%s - FPS: %.2f" %(moduleName,clock.get_fps()) )
          screen.fill(bgCol)
          spam()
  
  
          # Update our display:---------
          pygame.display.flip()
  
  #-------------------------------------------------------------------------------
  # Execution from shell\icon:
  if __name__ == "__main__":
      # Make running from IDE work better:
      thread = threading.Thread(target=read_from_port, args=(ser,))
      thread.start()
      sys.exit(main())
  </code></pre>
  
  <p>Can anyone help me understand where I'm going wrong here?</p>