forked from johncobb/echobaseppp
/
cptaskmanager.py
242 lines (184 loc) · 8.78 KB
/
cptaskmanager.py
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
import threading
import time
import Queue
import json
import cpcobs
import cpdb
import binascii
from datetime import datetime
from cpdb import CpDb
from cpdb import CpDbManager
from cprfmsg import CpRfMsgHeader
from cprfmsg import CpRfMsg
from cprfmsg import CpEncoder
from cpdefs import CpSystemState
from cpdefs import CpDefs
from cpstats import CpInetStats
def dataReceived(rf_data):
pass
def checksum(data):
cs = 0x00
sentence = data[:-1]
if(CpDefs.LogVerboseTaskMgr):
print 'sentence: ', sentence.encode('hex')
for s in sentence:
cs ^= ord(s)
if(CpDefs.LogVerboseTaskMgr):
print 'checksum', cs
return cs
def checksumValid(data):
cs = checksum(data)
return (ord(data[len(data)-1]) == cs)
class CpTaskManager(threading.Thread):
def __init__(self, rfThread, inetThread, dbThread, ledThread, *args):
self._target = self.task_handler
self._args = args
self.__lock = threading.Lock()
self.messages = Queue.Queue(10)
self.closing = False # A flag to indicate thread shutdown
self.rfThread = rfThread
self.ledThread = ledThread
self.inetThread = inetThread
self.inetThread.setStateChangedCallback(self.stateChangedCallback)
self.dbThread = dbThread
self.dctMessages = {}
self.start_time = time.strftime("%d/%m/%Y %H:%M:%S")
threading.Thread.__init__(self)
def stateChangedCallback(self, state):
if(state == CpSystemState.WAITNETWORKINTERFACE):
self.ledThread.startup()
elif(state == CpSystemState.CONNECT):
self.ledThread.connecting()
elif(state == CpSystemState.IDLE):
self.ledThread.idle()
elif(state == CpSystemState.SEND):
self.ledThread.sending()
elif(state == CpSystemState.SLEEP):
self.ledThread.sleep()
def run(self):
self._target(*self._args)
def task_handler(self):
# Toggle led startup pattern
self.ledThread.startup()
while not self.closing:
# Process new messages
self.handler_rfqueue()
time.sleep(.0005)
def handler_rfqueue(self):
rf_encoded = self.rfThread.queue_get()
# TODO: Sanity check (Redundant: checked in cprf.py)
if(len(rf_encoded) >= CpDefs.RfMsgLen):
# Decode cobs encoding
rf_decoded = cpcobs.decode(rf_encoded)
# Validate checksum
if (checksumValid(rf_decoded) == False):
print 'Invalid Checksum'
return
if(CpDefs.LogVerboseTaskMgr):
print 'Queued Message Received!!!'
try:
#self.handleNetworkThrottlingMacAddress(rf_decoded)
self.handleNetworkThrottlingCompositeAddress(rf_decoded)
except Exception, e:
print "CpTaskManager::handler_rfqueue ERROR: ", e
# Throttle network traffic based upon the tag's extAddr (Mac Address)
# This keeps messages from constantly being reported to the server
def handleNetworkThrottlingMacAddress(self, rf_decoded):
# NEW CODE TO THROTTLE NETWORK TRAFFIC
# We just need to load the header to store in the dictionary
# this will cut down on the amount of memory used when searching
# for tags
msg = CpRfMsgHeader(rf_decoded)
if(msg.extAddr in self.dctMessages):
# We found the mac address in the dictionary
if((datetime.now() - self.dctMessages[msg.extAddr].timestamp).seconds >= CpDefs.RfMsgThrottleTimeout):
# Update the timestamp for the message in the dictionary
self.dctMessages[msg.extAddr].timestamp = datetime.now()
self.dbThread.enqueue_record(rf_decoded)
if(CpDefs.LogVerboseTaskMgr):
print 'SENDING MESSAGE AFTER TIMEOUT'
else:
if(CpDefs.LogVerboseTaskMgr):
print 'NEW MESSAGE RECEIVED'
# Add the new message to the dictionary
self.dctMessages[msg.extAddr] = msg
# Enqueue the message for sending
self.dbThread.enqueue_record(rf_decoded)
# END NEW CODE TO THROTTLE NETWORK TRAFFIC
# Throttle network traffic based upon a composite key defined by extAddr and routerAddr
# This allows tag messages that have been reported via different router end points to
# bypass the RfMsgThrottleTimeout and be sent to the server
def handleNetworkThrottlingCompositeAddress(self, rf_decoded):
# NEW CODE TO THROTTLE NETWORK TRAFFIC
# We just need to load the header to store in the dictionary
# this will cut down on the amount of memory used when searching
# for tags
msg = CpRfMsg(rf_decoded)
# Check for Composite Address (extAddr + routerAddr)
if(msg.compAddress in self.dctMessages):
# We found the composite address in the dictionary
#check if it is time to send messages
if((datetime.now() - self.dctMessages[msg.compAddress].timestamp).seconds >= CpDefs.RfMsgThrottleTimeout):
# handle send messages
for key in self.dctMessages:
#average rssi and insert into raw data
self.dctMessages[key].smoothRssi()
#enqueue updated raw data with averaged rssi
self.dbThread.enqueue_record(self.dctMessages[key].raw)
#empty dictionary
self.dctMessages.clear()
if(CpDefs.LogVerboseTaskMgr):
print 'SENDING MESSAGE AFTER TIMEOUT'
else:
#handle entry update
self.handle_new_message(msg)
else:
#entry not found, create a new entry
if(CpDefs.LogVerboseTaskMgr):
print 'NEW MESSAGE RECEIVED'
# Add the new message to the dictionary
self.dctMessages[msg.compAddress] = msg
# END NEW CODE TO THROTTLE NETWORK TRAFFIC
def handle_new_message (self, msg):
#sum rssi values
msg.rssi = msg.rssi + self.dctMessages[msg.compAddress].rssi
#increment count
msg.count = self.dctMessages[msg.compAddress].count + 1
#replace entry with new updated entry
self.dctMessages[msg.compAddress] = msg
#update timestamp
self.dctMessages[msg.compAddress].timestamp = datetime.now()
def getRfThread(self):
return self.rfThread
def getDbThread(self):
return self.dbThread
def getInetThread(self):
return self.inetThread
def getLedThread(self):
return self.ledThread
def enqueue_message(self, cmd):
try:
self.messages.put(cmd, block=True, timeout=1)
except:
self.__lock.acquire()
print "CpTaskManager messages queue is full"
self.__lock.release()
def logStats(self):
print '#### System Status Report ####'
print '## Startup:', self.start_time
print '## CpRf.QueueDepth = ', self.getRfThread().get_queue_depth()
print '## CpDb.QueueDepth = ', self.getDbThread().get_queue_depth()
print '## CpInet.QueueDepth = ', self.getInetThread().get_queue_depth()
print '## CpInet.CurrentState = ', self.getInetThread().get_current_state()
print '## CpInet.Sent = ', self.getInetThread().get_inet_stats().Sent
#print '## CpInet.LastSent =', self.getInetThread().get_inet_stats().LastSent.strftime("%d/%m/%Y %H:%M:%S")
print '## CpInet.SendErrors = ', self.getInetThread().get_inet_stats().SendErrors
print '## CpInet.InitErrors = ', self.getInetThread().get_inet_stats().InitErrors
print '## CpInet.ConnectErrors = ', self.getInetThread().get_inet_stats().ConnectErrors
print '##', time.strftime("%d/%m/%Y %H:%M:%S")
print '#### End System Status Report ####'
def shutdown_thread(self):
print 'shutting down CpTaskManager...'
self.__lock.acquire()
self.closing = True
self.__lock.release()