Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/firmata.py
diff options
context:
space:
mode:
Diffstat (limited to 'firmata.py')
-rwxr-xr-xfirmata.py167
1 files changed, 167 insertions, 0 deletions
diff --git a/firmata.py b/firmata.py
new file mode 100755
index 0000000..756c714
--- /dev/null
+++ b/firmata.py
@@ -0,0 +1,167 @@
+#! /usr/bin/env python
+
+"""
+Python API for the Firmata protocol
+Copyright (C) 2008 laboratorio (info@laboratorio.us)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+__version__ = "0.3"
+
+import time
+import serial
+
+DIGITAL_MESSAGE = 0x90 # send data for a digital port
+ANALOG_MESSAGE = 0xE0 # send data for an analog pin (or PWM)
+REPORT_ANALOG = 0xC0 # enable analog input by pin #
+REPORT_DIGITAL = 0xD0 # enable digital input by port
+SET_PIN_MODE = 0xF4 # set a pin to INPUT/OUTPUT/PWM/etc
+REPORT_VERSION = 0xF9 # report firmware version
+SYSTEM_RESET = 0xFF # reset from MIDI
+START_SYSEX = 0xF0 # start a MIDI SysEx message
+END_SYSEX = 0xF7 # end a MIDI SysEx message
+
+# pin modes
+INPUT = 0
+OUTPUT = 1
+PWM = 2
+SERVO = 3
+
+LOW = 0
+HIGH = 1
+MAX_DATA_BYTES = 32
+
+class Arduino:
+
+ def __init__(self, port, baudrate=115200):
+
+ self.serial = serial.Serial(port, baudrate, bytesize=8, timeout=2)
+
+ self.wait_for_data = 0
+ self.exec_multibyte_cmd = 0
+ self.multibyte_channel = 0
+ self.stored_input_data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0 ]
+ self.parsing_sysex = False
+ self.sysex_bytes_read = 0
+ self.digital_output_data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ self.digital_input_data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ self.analog_input_data = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ self.major_version = 0
+ self.minor_version = 0
+ self.__report()
+
+ def __str__(self):
+ return "Arduino: %s" % self.serial.port
+
+ def pin_mode(self, pin, mode):
+ """Setting mode to pin"""
+ self.serial.write(chr(SET_PIN_MODE))
+ self.serial.write(chr(pin))
+ self.serial.write(chr(mode))
+
+ def digital_read(self, pin):
+ """Reading from digital pin"""
+ return (self.digital_input_data[pin >> 3] >> (pin & 0x07)) & 0x01
+
+ def digital_write(self, pin, value):
+ """Writing to a digital pin"""
+
+ port_number = (pin >> 3) & 0x0F
+
+ if value == 0:
+ self.digital_output_data[port_number] = self.digital_output_data[port_number] & ~(1 << (pin & 0x07))
+ else:
+ self.digital_output_data[port_number] = self.digital_output_data[port_number] | (1 << (pin & 0x07))
+
+ self.serial.write(chr(DIGITAL_MESSAGE | port_number))
+ self.serial.write(chr(self.digital_output_data[port_number] & 0x7F))
+ self.serial.write(chr(self.digital_output_data[port_number] >> 7))
+
+ def analog_read(self, pin):
+ """Reading from analog pin"""
+ return self.analog_input_data[pin]
+
+ def analog_write(self, pin, value):
+ """Writing to a analog pin"""
+ self.serial.write(chr(ANALOG_MESSAGE | (pin & 0x0F)))
+ self.serial.write(chr(value & 0x7F))
+ self.serial.write(chr(value >> 7))
+
+ def set_version(self, major, minor):
+ """Setting a minor and major version"""
+ self.major_version = major
+ self.minor_version = minor
+
+ def available(self):
+ """Checking serial connection status"""
+ return self.serial.isOpen()
+
+ def delay(self, secs):
+ """Waiting in seconds"""
+ time.sleep(secs)
+
+ def parse(self):
+ """Preparing the data to be handled"""
+ data = self.serial.read()
+ if data != "":
+ self.__process(ord(data))
+
+ def __process(self, input_data):
+ """Handling input data"""
+ command = None
+
+ if self.parsing_sysex:
+ if input_data == END_SYSEX:
+ self.parsing_sysex = False
+ else:
+ self.stored_input_data[self.sysex_bytes_read] = input_data
+ self.sysex_bytes_read += 1
+
+ elif self.wait_for_data > 0 and input_data < 128:
+ self.wait_for_data -= 1
+ self.stored_input_data[self.wait_for_data] = input_data
+
+ if self.exec_multibyte_cmd != 0 and self.wait_for_data == 0:
+ if self.exec_multibyte_cmd == DIGITAL_MESSAGE:
+ self.digital_input_data[self.multibyte_channel] = (self.stored_input_data[0] << 7) + self.stored_input_data[1]
+ elif self.exec_multibyte_cmd == ANALOG_MESSAGE:
+ self.analog_input_data[self.multibyte_channel] = (self.stored_input_data[0] << 7) + self.stored_input_data[1]
+ elif self.exec_multibyte_cmd == REPORT_VERSION:
+ self.set_version(self.stored_input_data[1], self.stored_input_data[0])
+ else:
+ if input_data < 0xF0:
+ command = input_data & 0xF0
+ self.multibyte_channel = input_data & 0x0F
+ else:
+ command = input_data # commands in the 0xF* range don't use channel data
+
+ if command == DIGITAL_MESSAGE or \
+ command == ANALOG_MESSAGE or \
+ command == REPORT_VERSION:
+ self.wait_for_data = 2
+ self.exec_multibyte_cmd = command
+
+ def __report(self):
+ """Reporting analog and digital pins"""
+
+ self.delay(2)
+ for port in range(6):
+ self.serial.write(chr(REPORT_ANALOG | port))
+ self.serial.write(chr(1))
+
+ for port in range(2):
+ self.serial.write(chr(REPORT_DIGITAL | port))
+ self.serial.write(chr(1))