-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdisplay.py
279 lines (227 loc) · 9.17 KB
/
display.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#!/usr/bin/env python3
# -*- coding: utf8 -*-
#
# A demo texting program in python for the REYAX RYLR998 LoRa® module.
# Get on the air with a Rasperry Pi 4 Model B Rev 1.5, a RYLR998 module,
# five wires and ten female-female GPIO connectors.
#
# Written by Florian Lengyel, WM2D
#
# This software is released under an MIT license.
# See the accompanying LICENSE.txt file.
#
# This is the Display class
import curses as cur
import _curses
import curses.ascii
import locale
locale.setlocale(locale.LC_ALL, '')
#stdscr.addstr(0, 0, mystring.encode('UTF-8'))
class Display:
# color pair initialization constants
WHITE_BLACK = 0 # built in cannot change
YELLOW_BLACK = 1
GREEN_BLACK = 2 # our pallete is off bear with me
BLUE_BLACK = 3
RED_BLACK = 4 # Pardon the kpop reference below
BLACK_PINK = 5 # received text is really magenta on black
WHITE_RED = 6
WHITE_GREEN = 7
ONESEC = 1
HALFSEC = 0.5
FOURTHSEC = 0.25
TENTHSEC = 0.1
CENTISEC = 0.01
# status window (stwin) labels
# coordinates are relative to the stwin
TXRX_LBL = " LoRa "
TXRX_LEN = 6
TXRX_ROW = 0
TXRX_COL = 0
ADDR_LBL = "ADDR"
ADDR_LEN = 4
ADDR_COL = 8
RSSI_COL = 21
RSSI_LBL = "RSSI"
RSSI_LEN = 4
SNR_COL = 32
SNR_LBL = "SNR"
SNR_LEN = 3
VFO_LBL = "VFO"
VFO_LEN = 3
VFO_ROW = 2
VFO_COL = 1
PWR_LBL = "PWR"
PWR_LEN = 3
PWR_ROW = 2
PWR_COL = 17
NETID_LBL = "NETWORK ID"
NETID_LEN = 10
NETID_ROW = 2
NETID_COL = 26
MAX_ROW = 28
MAX_COL = 42
# this needs to be part of the Display class
rxrow = 0 # rxwin_y relative window coordinates
rxcol = 0 # rxwin_x
maxrow = MAX_ROW
maxcol = MAX_COL
bdrwin = None # the outer window.
rxwin = None # receive window
txwin = None # transmit window
stwin = None # status window
# receive and transmit window border initialization
# The next two inner functions restrict access to the receive
# and transmit window border variables rxbdr and txbdr, resp.,
# and return the derived receive and transmit windows
# rxwin and txwin, respectively.
# Relative coordinates are congenial - might remove magic numbers
def derive_bdrwin(self, scr:_curses) -> None:
bdrwin = scr.derwin(self.maxrow,self.maxcol,0,0)
self.bdrwin = bdrwin
def draw_border(self) -> None:
# define the border in one place. Program from outer to inner.
self.bdrwin.border()
# Fill in the details
# receive window border
self.bdrwin.addch(21,0, cur.ACS_LTEE)
self.bdrwin.hline(21,1,cur.ACS_HLINE,self.maxcol-2)
self.bdrwin.addch(21,self.maxcol-1, cur.ACS_RTEE)
# status window border
# second line
self.bdrwin.addch(23,0, cur.ACS_LTEE)
self.bdrwin.hline(23,1,cur.ACS_HLINE,self.maxcol-2)
self.bdrwin.addch(23,self.maxcol-1, cur.ACS_RTEE)
# transmit window border
# third line
self.bdrwin.addch(25, 0, cur.ACS_LTEE)
self.bdrwin.hline(25, 1, cur.ACS_HLINE,self.maxcol-2)
self.bdrwin.addch(25, self.maxcol-1, cur.ACS_RTEE)
# status labels
fg_bg = cur.color_pair(self.WHITE_BLACK)
self.bdrwin.addnstr(22, self.TXRX_COL+1, self.TXRX_LBL, self.TXRX_LEN, fg_bg)
self.bdrwin.addch(21, 7, cur.ACS_TTEE)
self.bdrwin.vline(22, 7, cur.ACS_VLINE, 1, fg_bg)
self.bdrwin.addch(23, 7, cur.ACS_BTEE)
self.bdrwin.addnstr(22, self.ADDR_COL+1, self.ADDR_LBL, self.ADDR_COL, fg_bg)
self.bdrwin.addch(21, 20, cur.ACS_TTEE)
self.bdrwin.vline(22, 20, cur.ACS_VLINE, 1, fg_bg)
self.bdrwin.addch(23, 20, cur.ACS_BTEE)
self.bdrwin.addnstr(22, self.RSSI_COL+1, self.RSSI_LBL, self.RSSI_LEN, fg_bg)
self.bdrwin.addch(21, 31, cur.ACS_TTEE)
self.bdrwin.vline(22, 31, cur.ACS_VLINE, 1, fg_bg)
self.bdrwin.addch(23, 31, cur.ACS_BTEE)
self.bdrwin.addnstr(22, self.SNR_COL+1, self.SNR_LBL, self.SNR_LEN, fg_bg)
self.bdrwin.addnstr(24, self.VFO_COL+1, self.VFO_LBL, self.VFO_LEN, fg_bg)
self.bdrwin.addch(23, 16, cur.ACS_TTEE)
self.bdrwin.addch(24, 16, cur.ACS_VLINE)
self.bdrwin.addch(25, 16, cur.ACS_BTEE)
self.bdrwin.addnstr(24, self.PWR_COL+1, self.PWR_LBL, self.PWR_LEN, fg_bg)
self.bdrwin.addch(23, 25, cur.ACS_TTEE)
self.bdrwin.addch(24, 25, cur.ACS_VLINE)
self.bdrwin.addch(25, 25, cur.ACS_BTEE)
self.bdrwin.addnstr(24, self.NETID_COL+1, self.NETID_LBL, self.NETID_LEN, fg_bg)
self.bdrwin.noutrefresh()
def derive_rxwin(self) -> None:
#rxbdr = scr.derwin(22,42,0,0)
# window.border([ls[, rs[, ts[, bs[, tl[, tr[, bl[, br]]]]]]]])
self.rxwin = self.bdrwin.derwin(20,40,1,1)
self.rxwin.scrollok(True)
self.rxwin.bkgd(' ', cur.color_pair(self.YELLOW_BLACK)) # set bg color
self.rxwin.noutrefresh() # updates occur in one place in the xcvr() loop
# move up to avoid overwriting
def rxScrollUp(self) -> None:
row, col = self.rxwin.getyx()
if row == 19:
self.rxwin.scroll()
def rxNextRow(self) -> None:
# set rxrow, rxcol
row, col = self.rxwin.getyx()
self.rxrow = min(19, row+1)
self.rxcol = 0 # never moves
def rxaddnstr(self, msg, msglen, fg_bg = BLUE_BLACK) -> None:
self.rxScrollUp()
self.rxwin.addnstr(self.rxrow, self.rxcol, msg, msglen, cur.color_pair(fg_bg))
self.rxNextRow()
self.rxwin.noutrefresh()
def rxinsnstr(self, msg, msglen, fg_bg = BLUE_BLACK) -> None:
self.rxScrollUp()
self.rxwin.insnstr(self.rxrow, self.rxcol, msg, msglen, cur.color_pair(fg_bg))
self.rxNextRow()
self.rxwin.noutrefresh()
def derive_txwin(self) -> _curses.window:
txwin = self.bdrwin.derwin(1,self.maxcol-2,26,1)
self.txwin = txwin
# transmit window initialization
txwin.nodelay(True)
txwin.keypad(True)
# I'd prefer not timing out ESC, but there is no choice.
txwin.notimeout(False)
txwin.bkgd(' ', cur.color_pair(self.YELLOW_BLACK))
txwin.noutrefresh()
# status "window" setup
def derive_stwin(self) -> None:
stwin = self.bdrwin.derwin(3,self.maxcol-2,22,1)
self.stwin = stwin
fg_bg = cur.color_pair(self.WHITE_BLACK)
self.stwin.bkgd(' ', fg_bg)
self.stwin.noutrefresh()
def __init__(self, scr) -> None:
cur.savetty() # this has become necessary here
cur.raw() # raw, almost vegan character handling needed
scr.nodelay(True) # non-blocking getch()
scr.bkgd(' ', cur.color_pair(self.WHITE_BLACK))
# we compromise by setting the ESC delay to 1 msec
# we do not want to miss any received characters
# windows-curses does not implement set_escdelay()
##cur.set_escdelay(1) # An eternity for a CPU.
cur.start_color()
cur.use_default_colors()
cur.init_color(cur.COLOR_RED,1000,0,0)
cur.init_color(cur.COLOR_GREEN,0,1000,0)
cur.init_color(cur.COLOR_BLUE,0,0,1000)
# define fg,bg pairs
cur.init_pair(self.YELLOW_BLACK, cur.COLOR_YELLOW, cur.COLOR_BLACK) # user text
cur.init_pair(self.GREEN_BLACK, cur.COLOR_BLUE, cur.COLOR_BLACK)
cur.init_pair(self.BLUE_BLACK, cur.COLOR_GREEN, cur.COLOR_BLACK) # status indicator
cur.init_pair(self.RED_BLACK, cur.COLOR_RED, cur.COLOR_BLACK) # errors
cur.init_pair(self.BLACK_PINK, cur.COLOR_MAGENTA, cur.COLOR_BLACK) # received text
cur.init_pair(self.WHITE_RED, cur.COLOR_WHITE, cur.COLOR_RED)
cur.init_pair(self.WHITE_GREEN, cur.COLOR_WHITE, cur.COLOR_GREEN)
self.derive_bdrwin(scr)
self.draw_border()
self.derive_rxwin()
self.derive_stwin()
self.derive_txwin()
def xlateError(self, err_code: str) -> None:
match err_code:
case '1':
err_str = "AT command missing 0x0D 0x0A."
case '2':
err_str = "AT command missing 'AT'."
case '4':
err_str = "Unknown AT command."
case '5':
err_str = "Data length specified does not match the data length."
case '10':
err_str = "Transmit time exceeds limit."
case '12':
err_str = "CRC error on receive."
case '13':
err_str = "TX data exceeds 240 bytes."
case '14':
err_str = "Failed to write flash memory."
case '15':
err_str = "Unknown failure."
case '17':
err_str = "Last TX was not completed."
case '18':
err_str = "Preamble value is not allowed."
case '19':
err_str = "RX failure. Header error."
case '20':
err_str = "Invalid time in MODE 2 setting."
case _:
err_str = "Unknown error code."
err_string = "ERR={}: {}".format(err_code, err_str)
self.rxaddnstr(err_string, len(err_string), fg_bg=self.RED_BLACK)