- added support for TCP connection through Ev3Server
git-svn-id: http://moon:8086/svn/software/trunk/projects/opencv@340 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
+179
-139
@@ -2,47 +2,50 @@
|
|||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
|
|
||||||
Make sure your sdp includes an SP (serial port):
|
Make sure your sdp includes an SP (serial port):
|
||||||
% sdptool browse local
|
% sdptool browse local
|
||||||
...
|
...
|
||||||
Service Name: Serial Port
|
Service Name: Serial Port
|
||||||
Service Description: COM Port
|
Service Description: COM Port
|
||||||
|
|
||||||
If not:
|
If not:
|
||||||
% sdptool add SP
|
% sdptool add SP
|
||||||
|
|
||||||
Then:
|
Then:
|
||||||
% hcitool scan
|
% hcitool scan
|
||||||
...
|
...
|
||||||
XX:XX:XX:XX:XX:XX EV3
|
XX:XX:XX:XX:XX:XX EV3
|
||||||
|
|
||||||
% sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX
|
% sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX
|
||||||
|
|
||||||
Now /dev/rfcomm0 can be opened and closed like a normal serial port.
|
Now /dev/rfcomm0 can be opened and closed like a normal serial port.
|
||||||
The opposite action is:
|
The opposite action is:
|
||||||
% sudo rfcomm release /dev/rfcomm0
|
% sudo rfcomm release /dev/rfcomm0
|
||||||
|
|
||||||
EXAMPLE USAGE:
|
EXAMPLE USAGE:
|
||||||
from ev3 import *
|
from ev3 import *
|
||||||
|
|
||||||
with ev3.EV3() as brick:
|
with ev3.EV3() as brick:
|
||||||
# Create DirectCommand objects and add commands to them.
|
# Create DirectCommand objects and add commands to them.
|
||||||
cmd = direct_command.DirectCommand()
|
cmd = direct_command.DirectCommand()
|
||||||
cmd.add_ui_draw_update()
|
cmd.add_ui_draw_update()
|
||||||
cmd.send(brick)
|
cmd.send(brick)
|
||||||
|
|
||||||
# Call single DirectCommand functions without creating DirectCommand
|
# Call single DirectCommand functions without creating DirectCommand
|
||||||
# objects each time.
|
# objects each time.
|
||||||
brick.output_stop(direct_command.OutputPort.PORT_C,
|
brick.output_stop(direct_command.OutputPort.PORT_C,
|
||||||
direct_command.StopType.BRAKE)
|
direct_command.StopType.BRAKE)
|
||||||
|
|
||||||
# Call single system_command functions.
|
# Call single system_command functions.
|
||||||
brick.write_mailbox('foo', (0,1,2,3,4,5,6,7,8,9,0))
|
brick.write_mailbox('foo', (0,1,2,3,4,5,6,7,8,9,0))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
import serial
|
import serial
|
||||||
|
import socket
|
||||||
|
import array
|
||||||
|
|
||||||
import message
|
import message
|
||||||
import system_command
|
import system_command
|
||||||
@@ -50,139 +53,176 @@ import direct_command
|
|||||||
|
|
||||||
|
|
||||||
class KnownPaths(object):
|
class KnownPaths(object):
|
||||||
"""These are the default directories on the brick. All paths are
|
"""These are the default directories on the brick. All paths are
|
||||||
relative to 'lms2012/sys' by default.
|
relative to 'lms2012/sys' by default.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
DEFAULT_PATH = "." # lms2012/sys
|
DEFAULT_PATH = "." # lms2012/sys
|
||||||
PROJECTS_PATH = "../prjs" # lms2012/prjs
|
PROJECTS_PATH = "../prjs" # lms2012/prjs
|
||||||
APPS_PATH = "../apps" # lms2012/apps
|
APPS_PATH = "../apps" # lms2012/apps
|
||||||
TOOLS_PATH = "../tools" # lms2012/tools
|
TOOLS_PATH = "../tools" # lms2012/tools
|
||||||
SOURCE_PATH = "../source" # lms2012/source
|
SOURCE_PATH = "../source" # lms2012/source
|
||||||
|
|
||||||
|
|
||||||
class EV3Error(Exception):
|
class EV3Error(Exception):
|
||||||
"""Subclass for reporting errrors."""
|
"""Subclass for reporting errrors."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Port(object):
|
||||||
|
RFCOMM_BAUDRATE = 115200
|
||||||
|
|
||||||
|
def __init__(self, port_str):
|
||||||
|
self._port_str = port_str
|
||||||
|
self.sock = None
|
||||||
|
self.mode = 'Unknown'
|
||||||
|
if (self.sock is None):
|
||||||
|
try:
|
||||||
|
addr = self._port_str.split(':')
|
||||||
|
_ = socket.inet_aton(addr[0])
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
|
self.sock.connect((addr[0], int(addr[1])))
|
||||||
|
self.mode = "TCP"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.sock = serial.Serial(port=self._port_str,
|
||||||
|
baudrate=self.RFCOMM_BAUDRATE,
|
||||||
|
bytesize=serial.EIGHTBITS,
|
||||||
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
timeout=None,
|
||||||
|
xonxoff=False,
|
||||||
|
rtscts=False,
|
||||||
|
writeTimeout=None,
|
||||||
|
dsrdtr=False,
|
||||||
|
interCharTimeout=None)
|
||||||
|
|
||||||
|
self.mode = 'Serial'
|
||||||
|
|
||||||
|
def read(self, size, timeout=1.0):
|
||||||
|
if self.mode == 'Serial':
|
||||||
|
return self.sock.read(size)
|
||||||
|
elif self.mode == 'TCP':
|
||||||
|
return self.sock.recv(size)
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
if self.mode == 'Serial':
|
||||||
|
return self.sock.write(data)
|
||||||
|
elif self.mode == 'TCP':
|
||||||
|
byte = array.array('B', data).tostring()
|
||||||
|
return self.sock.send(byte)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if (self.sock is not None):
|
||||||
|
self.sock.close()
|
||||||
|
self.sock = None
|
||||||
|
|
||||||
class EV3(object):
|
class EV3(object):
|
||||||
""""""
|
""""""
|
||||||
DEFAULT_RFCOMM_PORT = '/dev/rfcomm0'
|
DEFAULT_RFCOMM_PORT = '/dev/rfcomm0'
|
||||||
RFCOMM_BAUDRATE = 115200
|
|
||||||
|
def __init__(self, port_str=DEFAULT_RFCOMM_PORT):
|
||||||
|
"""Creates a new object but doesn't open the port."""
|
||||||
|
self._port_str = port_str
|
||||||
|
self._port = None
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, port_str=DEFAULT_RFCOMM_PORT):
|
def open(self):
|
||||||
"""Creates a new object but doesn't open the port."""
|
"""Opens the object's serial port."""
|
||||||
self._port_str = port_str
|
if (self._port is None):
|
||||||
self._port = None
|
self._port = Port(self._port_str)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Closes the object's serial port."""
|
||||||
|
if (self._port is not None):
|
||||||
|
del self._port
|
||||||
|
self._port = None
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
def send_message(self, msg, message_counter=0x1234):
|
||||||
"""Opens the object's serial port."""
|
"""Allows for sending raw messages to the EV3. The msg parameter should
|
||||||
if (self._port is None):
|
be an array of byte values. The msg parameter should not include the
|
||||||
self._port = serial.Serial(port=self._port_str,
|
length/message_counter header. Raises an EV3Error if the specified
|
||||||
baudrate=self.RFCOMM_BAUDRATE,
|
message is a type that expects a reply.
|
||||||
bytesize=serial.EIGHTBITS,
|
|
||||||
parity=serial.PARITY_NONE,
|
|
||||||
stopbits=serial.STOPBITS_ONE,
|
|
||||||
timeout=None,
|
|
||||||
xonxoff=False,
|
|
||||||
rtscts=False,
|
|
||||||
writeTimeout=None,
|
|
||||||
dsrdtr=False,
|
|
||||||
interCharTimeout=None)
|
|
||||||
|
|
||||||
def close(self):
|
"""
|
||||||
"""Closes the object's serial port."""
|
try:
|
||||||
if (self._port is not None):
|
message.send_message_no_reply(self._port, msg, message_counter)
|
||||||
self._port.close()
|
except message.MessageError as ex:
|
||||||
self._port = None
|
raise EV3Error(ex.message)
|
||||||
|
|
||||||
|
|
||||||
def send_message(self, msg, message_counter=0x1234):
|
def send_message_for_reply(self, msg, message_counter=0x1234):
|
||||||
"""Allows for sending raw messages to the EV3. The msg parameter should
|
"""Allows for sending raw messages to the EV3. The msg parameter should
|
||||||
be an array of byte values. The msg parameter should not include the
|
be an array of byte values. The msg parameter should not include the
|
||||||
length/message_counter header. Raises an EV3Error if the specified
|
length/message_counter header. Raises an EV3Error if the specified
|
||||||
message is a type that expects a reply.
|
message is a type that doesn't expect a reply.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
message.send_message_no_reply(self._port, msg, message_counter)
|
return message.send_message_for_reply(self._port,
|
||||||
except message.MessageError as ex:
|
msg,
|
||||||
raise EV3Error(ex.message)
|
message_counter)
|
||||||
|
except message.MessageError as ex:
|
||||||
|
raise EV3Error(ex.message)
|
||||||
|
|
||||||
|
|
||||||
def send_message_for_reply(self, msg, message_counter=0x1234):
|
def __dir__(self):
|
||||||
"""Allows for sending raw messages to the EV3. The msg parameter should
|
"""Add in functions from the system_command module as well as methods
|
||||||
be an array of byte values. The msg parameter should not include the
|
from the DirectCommand class because they can be called directly on an
|
||||||
length/message_counter header. Raises an EV3Error if the specified
|
EV3 object.
|
||||||
message is a type that doesn't expect a reply.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
result = dir(type(self))
|
||||||
return message.send_message_for_reply(self._port,
|
result += list(self.__dict__)
|
||||||
msg,
|
result += [s for s in list(system_command.__dict__)
|
||||||
message_counter)
|
if not s.startswith('_')]
|
||||||
except message.MessageError as ex:
|
result += [s[4:] for s in list(direct_command.DirectCommand.__dict__)
|
||||||
raise EV3Error(ex.message)
|
if s.startswith('add_')]
|
||||||
|
return sorted(set(result))
|
||||||
|
|
||||||
|
|
||||||
def __dir__(self):
|
def __getattr__(self, name):
|
||||||
"""Add in functions from the system_command module as well as methods
|
"""A little bit of magic is used in order to make it easier to work with
|
||||||
from the DirectCommand class because they can be called directly on an
|
EV3 objects.
|
||||||
EV3 object.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
result = dir(type(self))
|
if (hasattr(system_command, name)):
|
||||||
result += list(self.__dict__)
|
# This allows functions from the system_command module to be called
|
||||||
result += [s for s in list(system_command.__dict__)
|
# from an EV3 object i.e. ev3.list_files(KnownPaths.PROJECTS_PATH).
|
||||||
if not s.startswith('_')]
|
def execute_sc(*args):
|
||||||
result += [s[4:] for s in list(direct_command.DirectCommand.__dict__)
|
"""This is just a wrapper around an individual function from the
|
||||||
if s.startswith('add_')]
|
system_command module. See the system_command module for more
|
||||||
return sorted(set(result))
|
information.
|
||||||
|
|
||||||
|
"""
|
||||||
|
getattr(system_command, name)(self, *args)
|
||||||
|
|
||||||
|
return execute_sc
|
||||||
|
|
||||||
|
# This allows single functions from the DirectCommand class to be called
|
||||||
|
# from an EV3 object i.e. ev3.ui_draw_update().
|
||||||
|
dc_name = ('add_' + name)
|
||||||
|
if (hasattr(direct_command.DirectCommand, dc_name)):
|
||||||
|
def execute_dc(*args):
|
||||||
|
"""This is just a wrapper around an individual DirectCommand
|
||||||
|
method. See the DirectCommand class for more information.
|
||||||
|
|
||||||
|
"""
|
||||||
|
dc = direct_command.DirectCommand()
|
||||||
|
getattr(dc, dc_name)(*args)
|
||||||
|
return dc.send(self)
|
||||||
|
|
||||||
|
return execute_dc
|
||||||
|
|
||||||
|
return Object.__getattr__(self, name)
|
||||||
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __enter__(self):
|
||||||
"""A little bit of magic is used in order to make it easier to work with
|
self.open()
|
||||||
EV3 objects.
|
return self
|
||||||
|
|
||||||
"""
|
|
||||||
if (hasattr(system_command, name)):
|
|
||||||
# This allows functions from the system_command module to be called
|
|
||||||
# from an EV3 object i.e. ev3.list_files(KnownPaths.PROJECTS_PATH).
|
|
||||||
def execute_sc(*args):
|
|
||||||
"""This is just a wrapper around an individual function from the
|
|
||||||
system_command module. See the system_command module for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
"""
|
|
||||||
getattr(system_command, name)(self, *args)
|
|
||||||
|
|
||||||
return execute_sc
|
|
||||||
|
|
||||||
# This allows single functions from the DirectCommand class to be called
|
|
||||||
# from an EV3 object i.e. ev3.ui_draw_update().
|
|
||||||
dc_name = ('add_' + name)
|
|
||||||
if (hasattr(direct_command.DirectCommand, dc_name)):
|
|
||||||
def execute_dc(*args):
|
|
||||||
"""This is just a wrapper around an individual DirectCommand
|
|
||||||
method. See the DirectCommand class for more information.
|
|
||||||
|
|
||||||
"""
|
|
||||||
dc = direct_command.DirectCommand()
|
|
||||||
getattr(dc, dc_name)(*args)
|
|
||||||
return dc.send(self)
|
|
||||||
|
|
||||||
return execute_dc
|
|
||||||
|
|
||||||
return Object.__getattr__(self, name)
|
|
||||||
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __exit__(self, type, value, traceback):
|
||||||
self.open()
|
self.close()
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
self.close()
|
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ def append_str(byte_list, str_value):
|
|||||||
|
|
||||||
|
|
||||||
def _read_bytes(port, num_bytes):
|
def _read_bytes(port, num_bytes):
|
||||||
return [ord(i) for i in port.read(num_bytes)]
|
return port.read(num_bytes)
|
||||||
|
|
||||||
|
|
||||||
def _write_bytes(port, byte_seq):
|
def _write_bytes(port, byte_seq):
|
||||||
|
|||||||
Reference in New Issue
Block a user