Skip to content

Commit d976f25

Browse files
committed
Interface definition saving and loading prototype.
1 parent 95a6e18 commit d976f25

File tree

3 files changed

+57
-10
lines changed

3 files changed

+57
-10
lines changed

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ classifiers =
2020
[options]
2121
packages = find:
2222
install_requires =
23+
PyYAML==5.3.1
2324
pyserial==3.4
2425

2526
[options.entry_points]

simple_rpc/cli.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from json import dumps, loads
33
from json.decoder import JSONDecodeError
44
from sys import stdout
5-
from typing import BinaryIO
5+
from typing import BinaryIO, TextIO
66

77
from . import doc_split, usage, version
88
from .extras import json_utf8_decode, json_utf8_encode
@@ -48,22 +48,28 @@ def _loads(string: str) -> str:
4848
return string
4949

5050

51-
def rpc_list(handle: BinaryIO, device: str, baudrate: int, wait: int) -> None:
51+
def rpc_list(
52+
handle: BinaryIO, device: str, baudrate: int, wait: int, save: TextIO
53+
) -> None:
5254
"""List the device methods.
5355
5456
:arg handle: Output handle.
5557
:arg device: Device.
5658
:arg baudrate: Baud rate.
5759
:arg wait: Time in seconds before communication starts.
60+
:arg save: Interface definition file.
5861
"""
5962
with Interface(device, baudrate, wait) as interface:
60-
for method in interface.methods.values():
61-
handle.write(_describe_method(method) + '\n\n\n')
63+
if not save:
64+
for method in interface.methods.values():
65+
handle.write(_describe_method(method) + '\n\n\n')
66+
else:
67+
interface.save(save)
6268

6369

6470
def rpc_call(
6571
handle: BinaryIO, device: str, baudrate: int, wait: int, name: str,
66-
args: list) -> None:
72+
args: list, load: TextIO) -> None:
6773
"""Execute a method.
6874
6975
:arg handle: Output handle.
@@ -72,10 +78,11 @@ def rpc_call(
7278
:arg wait: Time in seconds before communication starts.
7379
:arg name: Method name.
7480
:arg args: Method parameters.
81+
:arg load: Interface definition file.
7582
"""
7683
args_ = list(map(lambda x: json_utf8_encode(_loads(x)), args))
7784

78-
with Interface(device, baudrate, wait) as interface:
85+
with Interface(device, baudrate, wait, True, load) as interface:
7986
result = interface.call_method(name, *args_)
8087

8188
if result is not None:
@@ -110,16 +117,22 @@ def _arg_parser() -> object:
110117
subparser = subparsers.add_parser(
111118
'list', formatter_class=ArgumentDefaultsHelpFormatter,
112119
parents=[common_parser], description=doc_split(rpc_list))
120+
subparser.add_argument(
121+
'-s', dest='save', type=FileType('w'), default=None,
122+
help='interface definition file')
113123
subparser.set_defaults(func=rpc_list)
114124

115125
subparser = subparsers.add_parser(
116126
'call', formatter_class=ArgumentDefaultsHelpFormatter,
117127
parents=[common_parser], description=doc_split(rpc_call))
118-
subparser.set_defaults(func=rpc_call)
119128
subparser.add_argument(
120129
'name', metavar='NAME', type=str, help='command name')
121130
subparser.add_argument(
122131
'args', metavar='ARG', type=str, nargs='*', help='command parameter')
132+
subparser.add_argument(
133+
'-l', dest='load', type=FileType('r'), default=None,
134+
help='interface definition file')
135+
subparser.set_defaults(func=rpc_call)
123136

124137
return parser
125138

simple_rpc/simple_rpc.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
from functools import wraps
22
from time import sleep
33
from types import MethodType
4+
from typing import TextIO
45

56
from serial import serial_for_url
67
from serial.serialutil import SerialException
8+
from yaml import safe_dump, safe_load
79

810
from .extras import make_function
911
from .io import read, read_byte_string, until, write
1012
from .protocol import parse_line
1113

1214

1315
_protocol = b'simpleRPC'
14-
_version = (3, 0, 0)
16+
_version = (3, 0, 0) # TODO: Replace tuples with lists for serialisation.
1517

1618
_list_req = 0xff
1719

@@ -20,17 +22,20 @@ class _Interface(object):
2022
"""Generic simpleRPC interface."""
2123
def __init__(
2224
self: object, device: str, baudrate: int=9600, wait: int=2,
23-
autoconnect: bool=True) -> None:
25+
autoconnect: bool=True, load: TextIO=None) -> None:
2426
"""
2527
:arg device: Device name.
2628
:arg baudrate: Baud rate.
2729
:arg wait: Time in seconds before communication starts.
2830
:arg autoconnect: Automatically connect.
31+
:arg load: Load interface definition from file.
2932
"""
3033
self._wait = wait
3134

3235
self._connection = serial_for_url(
3336
device, do_not_open=True, baudrate=baudrate)
37+
self._load = load
38+
# TODO: Put all of these in one object.
3439
self._version = (0, 0, 0)
3540
self._endianness = b'<'
3641
self._size_t = b'H'
@@ -118,7 +123,10 @@ def open(self: object) -> None:
118123
"""Connect to device."""
119124
sleep(self._wait)
120125

121-
self.methods = self._get_methods()
126+
if self._load:
127+
self.load()
128+
else:
129+
self.methods = self._get_methods()
122130
for method in self.methods.values():
123131
setattr(
124132
self, method['name'], MethodType(make_function(method), self))
@@ -160,6 +168,31 @@ def call_method(self: object, name: str, *args: list) -> any:
160168
return self._read(method['return']['fmt'])
161169
return None
162170

171+
def save(self: object, handle: TextIO) -> None:
172+
"""Save the interface definition to a file.
173+
174+
:arg handle: Open file handle.
175+
"""
176+
safe_dump(
177+
{
178+
'version': self._version,
179+
'endianness': self._endianness,
180+
'size_t': self._size_t,
181+
'methods': self.methods
182+
},
183+
handle, width=76, default_flow_style=False)
184+
185+
def load(self: object) -> None:
186+
"""Load the interface definition from a file.
187+
188+
:arg handle: Open file handle.
189+
"""
190+
definition = safe_load(self._load)
191+
self._version = definition['version']
192+
self._endianness = definition['endianness']
193+
self._size_t = definition['size_t']
194+
self.methods = definition['methods']
195+
163196

164197
class SerialInterface(_Interface):
165198
"""Serial simpleRPC interface."""

0 commit comments

Comments
 (0)