-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscan-speed-monitor.js
208 lines (186 loc) · 5.96 KB
/
scan-speed-monitor.js
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
import fetch from 'node-fetch'
import readline from 'readline'
import WebSocket from 'ws'
import argv from './args.js'
import * as util from './util.js'
const args = argv.parse('start-survey')
const start = (remoteAddr, survey) => {
return fetch(`http://${remoteAddr}/sklt/survey/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(survey)
})
.then(util.handleFetchResp)
.then(() => {
return fetch(`http://${remoteAddr}/sklt/config/`).then(resp => {
if (resp.ok) {
return resp.json()
}
return Promise.reject(`${resp.status} ${resp.statusText}`)
})
})
}
const rxPort = args['rx-port']
const surveyFile = args['survey-file']
const surveyParams = util.loadSurveyFile(surveyFile)
if (surveyParams == null) {
process.exit(1)
}
const openConn = config => {
// keep a collection of known PCIs
const knownCellDict = {}
const {
scanner_parameters: {
measurement_stop_policy,
measurement_num_detect_failures_limit,
measurement_detect_timeout
}
} = config
let phyIteration = 0
let cellsNotSeenThisPhyIter = {}
let cellCount = 0
let countDown = 0
let scanCount = 0
let cellId
let startTime = Date.now()
let lastPhyIterationComplete = startTime
const conn = new WebSocket(`ws://${args.remote}/events/`, ['sklt'])
conn.on('open', () => {
console.log('Connected to WebSocket')
console.log('----------------------')
console.log('\tStop Policy:\t\t', measurement_stop_policy)
console.log('\tFailure Limit:\t\t', measurement_num_detect_failures_limit)
console.log('\tFailure Timeout:\t', measurement_detect_timeout)
})
conn.on('close', () => {
console.error('Disconnected from WS')
})
conn.on('message', msg => {
const {
data: { event, type }
} = JSON.parse(msg)
if (type == 'scan') {
scanCount += 1
// create a key for the PCI reported in this scan event
cellId = `${event.tech}-${event.pci}-${event.frequency_mhz}`
// add cell to known list and count
if (knownCellDict[cellId] == null && event.mib != null) {
// this assumes that the first time we see a cell, it was decoded
knownCellDict[cellId] = refreshCell(event)
cellCount += 1
} else if (event.mib != null) {
// if the cell was already known and this is a decode event, update the
// decode time and iteration marker for this cell
knownCellDict[cellId] = refreshCell(event)
}
// if this cell hasn't been seen on this pass, yet, mark it and decrement
// the counter
if (cellsNotSeenThisPhyIter[cellId] === true) {
delete cellsNotSeenThisPhyIter[cellId]
countDown -= 1
} else if (countDown > 0) {
// if we're seeing cells that we've already seen on this pass, but we're
// still waiting on others, verify that the remaining cells haven't
// satisfied the measurement stop policy
for (let id in cellsNotSeenThisPhyIter) {
const isStale = checkIfCellIsStale(
knownCellDict[id],
event.scan_iteration,
measurement_stop_policy,
measurement_num_detect_failures_limit,
measurement_detect_timeout
)
// if this cell that we're waiting for has become stale, remove it
// from the known cells list and decrement the count down
if (isStale) {
delete knownCellDict[id]
delete cellsNotSeenThisPhyIter[id]
cellCount -= 1
countDown -= 1
}
}
}
// if all cells have been seen, restart the countdown
if (cellCount > 0 && countDown === 0) {
const lapTime = Date.now()
const timeSpan = lapTime - startTime
const avgLap = Math.round(timeSpan / (phyIteration + 1))
reprint(
'Phy Iteration Monitor',
'---------------------',
`\titeration:\t\t${phyIteration}`,
`\tcells:\t\t\t${cellCount}`,
`\titeration time (last):\t${lapTime - lastPhyIterationComplete} ms`,
`\titeration time (avg):\t${avgLap} ms`,
`\tscan_iteration:\t\t${event.scan_iteration}`,
`\traw scans:\t\t${(scanCount / timeSpan) * 1000}/s`
)
countDown = cellCount
cellsNotSeenThisPhyIter = resetAllNotSeen(knownCellDict)
lastPhyIterationComplete = lapTime
phyIteration += 1
}
}
})
}
const refreshCell = event => ({
decodeIteration: event.scan_iteration,
decodeTime: Date.now()
})
const resetAllNotSeen = knownCellDict =>
Object.keys(knownCellDict).reduce(
(newState, cellId) => ({
...newState,
[cellId]: true
}),
{}
)
const checkIfCellIsStale = (
cellInfo,
scan_iteration,
policy,
failLimit,
timeoutSeconds
) => {
switch (policy) {
case 'num_detect_failures':
return scan_iteration - cellInfo.decodeIteration >= failLimit
case 'detect_timeout':
// get the number of milliseconds that have lapsed since this cell's last
// decode and check if it is greater than the configured threshold
return (Date.now() - cellInfo.decodeTime) / 1000 >= timeoutSeconds
}
}
const print = (printer, ...args) => {
printer(...args)
resetPrintSpace = true
}
let resetPrintSpace = true
const reprint = (...lines) => {
// add space for stats, so we don't overwrite other stuff
if (resetPrintSpace) {
console.log('\n\n\n\n\n\n\n')
resetPrintSpace = false
}
// Move the cursor up by the number of lines
readline.moveCursor(process.stdout, 0, -lines.length)
// Clear the current line and print the new lines
for (const line of lines) {
readline.clearLine(process.stdout, 0)
readline.cursorTo(process.stdout, 0)
console.log(line)
}
}
const survey = {
address: '127.0.0.1:7531',
one_shot: false,
rx_port: rxPort,
survey_parameters: surveyParams
}
start(args.remote, survey).then(
config => openConn(config),
err => {
console.error(err)
process.exit(1)
}
)