remote.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. """
  2. gameduino.remote - remote interface
  3. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  4. The remote interface lets Python scripts read and write
  5. Gameduino memory, via the USB connection and a
  6. simple client running on the Arduino.
  7. The remote interface can be more convenient than compiling and uploading a
  8. Sketch when developing media and coprocessor microprograms::
  9. import gameduino.remote
  10. gd = gameduino.remote.Gameduino("/dev/ttyUSB0", 115200)
  11. gd.ascii()
  12. gd.putstr(0, 5, "Hello from Python")
  13. The Gameduino in this module is similar to the one in :mod:`gameduino.sim`.
  14. Because this module uses USB serial interface to communicate with the Arduino,
  15. it requires the `PySerial module <http://pyserial.sourceforge.net/>`_.
  16. .. image:: remote.png
  17. The Arduino runs a simple program ``memloader`` that
  18. listens for serial commands and accesses Gameduino memory.
  19. """
  20. import struct
  21. import serial
  22. import time
  23. import array
  24. from gameduino.registers import *
  25. from gameduino.base import BaseGameduino
  26. class Gameduino(BaseGameduino):
  27. def __init__(self, usbport, speed):
  28. self.ser = serial.Serial(usbport, speed)
  29. time.sleep(2)
  30. assert self.rd(IDENT) == 0x6d, "Missing IDENT"
  31. self.mem = array.array('B', [0] * 32768)
  32. self.coldstart()
  33. def wrstr(self, a, s):
  34. if not isinstance(s, str):
  35. s = s.tostring()
  36. self.mem[a:a+len(s)] = array.array('B', s)
  37. for i in range(0, len(s), 255):
  38. sub = s[i:i+255]
  39. ff = struct.pack(">BH", len(sub), 0x8000 | (a + i)) + sub
  40. self.ser.write(ff)
  41. def rd(self, a):
  42. """ Read byte at address ``a`` """
  43. ff = struct.pack(">BH", 1, a)
  44. self.ser.write(ff)
  45. return ord(self.ser.read(1))
  46. def rdstr(self, a, n):
  47. """
  48. Read ``n`` bytes starting at address ``a``
  49. :rtype: string of length ``n``.
  50. """
  51. r = ""
  52. while n:
  53. cnt = min(255, n)
  54. ff = struct.pack(">BH", cnt, a)
  55. self.ser.write(ff)
  56. r += self.ser.read(cnt)
  57. a += cnt
  58. n -= cnt
  59. return r
  60. def waitvblank(self):
  61. while self.rd(VBLANK) == 1:
  62. pass
  63. while self.rd(VBLANK) == 0:
  64. pass
  65. def linecrc(self, y):
  66. self.ser.write(struct.pack(">BBH", 0, ord('L'), y))
  67. return struct.unpack(">L", self.ser.read(4))[0]
  68. def coll(self):
  69. """
  70. Return the 256 bytes of COLLISION RAM.
  71. :rtype: list of byte values.
  72. """
  73. self.ser.write(struct.pack(">BB", 0, ord('c')))
  74. return array.array('B', self.ser.read(256)).tolist()
  75. def collcrc(self):
  76. self.ser.write(struct.pack(">BB", 0, ord('C')))
  77. return struct.unpack(">L", self.ser.read(4))[0]
  78. def memcrc(self, a, s):
  79. self.ser.write(struct.pack(">BBHH", 0, ord('M'), a, s))
  80. return struct.unpack(">L", self.ser.read(4))[0]
  81. def _im(self):
  82. """
  83. Return the current screen as a 400x300 RGB PIL Image::
  84. >>> import gameduino.sim
  85. >>> gd = gameduino.sim.Gameduino()
  86. >>> gd.im().save("screenshot.png")
  87. """
  88. import Image
  89. fi = Image.new("RGB", (400,300))
  90. for y in range(300):
  91. self.wr16(SCREENSHOT_Y, 0x8000 | y)
  92. while (self.rd16(SCREENSHOT_Y) & 0x8000) == 0:
  93. pass
  94. ld = array.array('H', self.rdstr(SCREENSHOT, 800))
  95. r = [8 * (31 & (v >> 10)) for v in ld]
  96. g = [8 * (31 & (v >> 5)) for v in ld]
  97. b = [8 * (31 & (v >> 0)) for v in ld]
  98. rgb = sum(zip(r,g,b), ())
  99. li = Image.fromstring("RGB", (400,1), array.array('B', rgb).tostring())
  100. fi.paste(li, (0, y))
  101. self.wr16(SCREENSHOT_Y, 0)
  102. return fi
  103. import array
  104. def readarray(filename):
  105. return array.array('B', open(filename).read())