-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsp_protocol.py
More file actions
182 lines (155 loc) · 5.03 KB
/
Copy pathsp_protocol.py
File metadata and controls
182 lines (155 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#
# Emulate a siteplayer on its serial link.
#
# Packet format is
# Command Byte
# Address 1 or 2 bytes
# Data 0 - 16 Bytes
#
#
import threading
import logging
_log = logging.getLogger(__file__)
import socket
class PacketTypes:
# extract packet type from byte
COMMAND_MASK = 0xF0
LENGTH_MASK = 0x0F
# single byte
NOP = 0x00
# Read status from SP, send a byte back
# bits are set by form pages.
Status = 0x10
# single byte
Reset = 0x20
# 4 bytes of data, 2 bytes baud and 2 byte turnaround delay
ComParams = 0x30
# trigger UDP send from udp buffer
UDPSend = 0x50
# single byte address and then up to 16 bytes of data
Write = 0x80
# two byte address(lo,high) and then up to 16 bytes of data
WriteX = 0x90
# write a single bit in address space at 0x2E0-0x2FF
# byte address and byte with bit in
WriteBit = 0xA0
# toggle a single bit in address space at 0x2E0-0x2FF
# byte address and byte ignored
ToggleBit = 0xB0
# single byte address and then receive up to 16 bytes of data
Read = 0xC0
# two byte address(lo,high) and then receive up to 16 bytes of data
ReadX = 0xD0
# read a single bit in address space at 0x2E0-0x2FF
# byte address and returns byte with bit in
ReadBit = 0xE0
class SpProtocolHandler(threading.Thread):
daemon = True
def __init__(self, io, callback):
super(SpProtocolHandler,self).__init__(name='SpProtocolHandler')
self._running = False
self._io = io
self._callback = callback
self._raw_data = bytearray(64*1024) # initial state
self.start()
def extract_len(self,command):
return (command & PacketTypes.LENGTH_MASK)+1
def update_data(self,address,data):
_log.debug("update_data %s: (%s)%s (%s)", address, len(data), data, type(data))
# update raw_data
self._raw_data[address:address+len(data)] = data
# call user to make other updates
if self._callback:
self._callback( address, len(data), self._raw_data)
def command_00(self,command):
# NOP
pass
def command_10(self,command):
# status, not used by webbrick
self._io.write( '\0' )
def command_20(self,command):
# Reset
pass
def command_30(self,command):
# ComParams
self._io.read(4) # throw away result
def command_40(self,command):
# unused
pass
def command_50(self,command):
to_address = '255.255.255.255'
to_port = 2552
b_loc = 0 # first thing
b_len = 32
#UDPSend
# locate the target address
# locate target port
# locate buffer location in self._raw_data
# open socket
# send UDP packet
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) as s:
s.sendto(self._raw_data[b_loc:b_loc+b_len].decode(), (to_address, to_port))
def command_60(self,command):
# unused
pass
def command_70(self,command):
# unused
pass
def command_80(self,command):
# write
address = self.read_short_address()
data = self._io.read( self.extract_len(command) )
self.update_data( address, data )
def command_90(self,command):
# writeX
address = self.read_long_address()
data = self._io.read( self.extract_len(command) )
self.update_data( address, data )
def command_A0(self,command):
# WriteBit
self._io.read(2) # throw away result
def command_B0(self,command):
# ToggleBit
self._io.read(2) # throw away result
def command_C0(self,command):
# Read
address = self.read_short_address()
self._io.write( self._raw_data[address:address+self.extract_len(command)])
def command_D0(self,command):
# ReadX
address = self.read_long_address()
self._io.write( self._raw_data[address:address+self.extract_len(command)])
def command_E0(self,command):
# readbit
pass
def command_F0(self,command):
# unsued
pass
def read_short_address(self):
return ord(self._io.read(1)[0])
def read_long_address(self):
address = self._io.read(2)
return ord(address[0]) + (ord(address[1])*256)
def read_packet(self):
command = self._io.read(1)
if len(command) > 0:
command = ord(command[0])
code = (command & PacketTypes.COMMAND_MASK)
command_name = "command_%2.2X" % (code,)
# desptahc to one of command_XX handlers above
_log.debug("read_packet %s", command_name)
getattr(self, command_name)(command)
def shutdown(self):
self._running = False
@property
def is_running(self):
return self._running
def run(self):
_log.debug("run")
self._running = True
try :
while self._running:
self.read_packet()
except Exception, ex:
_log.exception("run")
self._running = False