Coverage for pyilper/pilscope.py: 80%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

200 statements  

1#!/usr/bin/python3 

2# -*- coding: utf-8 -*- 

3# pyILPER 1.2.1 for Linux 

4# 

5# An emulator for virtual HP-IL devices for the PIL-Box 

6# derived from ILPER 1.4.5 for Windows 

7# Copyright (c) 2008-2013 Jean-Francois Garnier 

8# C++ version (c) 2013 Christoph Gießelink 

9# Python Version (c) 2015 Joachim Siebold 

10# 

11# This program is free software; you can redistribute it and/or 

12# modify it under the terms of the GNU General Public License 

13# as published by the Free Software Foundation; either version 2 

14# of the License, or (at your option) any later version. 

15# 

16# This program is distributed in the hope that it will be useful, 

17# but WITHOUT ANY WARRANTY; without even the implied warranty of 

18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19# GNU General Public License for more details. 

20# 

21# You should have received a copy of the GNU General Public License 

22# along with this program; if not, write to the Free Software 

23# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 

24# 

25 

26from PySide6 import QtWidgets 

27import datetime 

28from .pilconfig import PILCONFIG 

29from .pilwidgets import cls_tabtermgeneric, T_BOOLEAN, T_STRING,O_DEFAULT 

30from .pildevbase import cls_pildevbase 

31 

32# 

33# Scope tab object classes ---------------------------------------------------- 

34# 

35# Changelog 

36# 

37# 21.11.2015 jsi 

38# - introduced show IDY frames option in scope tab 

39# 28.04.2016 jsi 

40# - enable tabscope to log inbound, outbound and both traffic 

41# 29.04.2016 jsi 

42# - log scope unbuffered 

43# 01.08.2017 jsi 

44# - refactoring: tab classes moved to this file 

45# 03.09.2017 jsi 

46# - register pildevice is now method of comobject 

47# 14.09.2017 jsi 

48# - refactoring 

49# 22.09.2017 jsi 

50# - get actual number of columns with the get_cols method 

51# 23.09.2017 jsi 

52# - output hex code option added 

53# - fixed bug in form feed condition determination in out_scope 

54# 25.09.2017 jsi 

55# - extended options to display frames (mnemonic only, hex only, mnemonic and hex) 

56# 04.10.2017 jsi 

57# - display mode of scopes not initialized properly on program start 

58# 16.01.2018 jsi 

59# - adapted to cls_tabtermgeneric, implemented new cascading config menu 

60# 13.08.2018 jsi 

61# - log file tagging as proposed by Sylvain Cote 

62# 14.08.2018 jsi 

63# - added "**" to tag to find tags better in the logfile 

64# 16.01.2018 jsi 

65# - send int instead of char to terminal 

66 

67LOG_INBOUND=0 

68LOG_OUTBOUND=1 

69LOG_BOTH=2 

70DISPLAY_MNEMONIC=0 

71DISPLAY_HEX=1 

72DISPLAY_BOTH=2 

73log_mode= ["Inbound", "Outbound", "Both"] 

74display_mode= ["Mnemonic","Hex","Both"] 

75 

76class cls_tabscope(cls_tabtermgeneric): 

77 

78 def __init__(self,parent,name): 

79 super().__init__(parent,name) 

80 self.scope_charpos=0 

81# 

82# init local config parameters 

83# 

84 self.showIdy= PILCONFIG.get(self.name,"showidy",False) 

85 self.displayMode= PILCONFIG.get(self.name,"displaymode",DISPLAY_MNEMONIC) 

86 self.logMode=PILCONFIG.get(self.name,"logmode",LOG_INBOUND) 

87# 

88# add logging  

89# 

90 self.add_logging() 

91# 

92# add tag button 

93# 

94 self.tagButton=QtWidgets.QPushButton("Tag Logfile") 

95 self.add_controlwidget(self.tagButton) 

96 self.tagButton.setEnabled(False) 

97 self.tagButton.clicked.connect(self.do_tagbutton) 

98# 

99# add scope config options to cascading menu 

100# 

101 self.cBut.add_option("Show IDY frames","showidy",T_BOOLEAN,[True,False]) 

102 self.cBut.add_option("Display Mode","displaymode",T_STRING,display_mode) 

103 self.cBut.add_option("Log mode","logmode",T_STRING,log_mode) 

104# 

105# create HP-IL devices and let the GUI object know them 

106# 

107 self.pildevice= cls_pilscope(True,self) 

108 self.pildevice2= cls_pilscope(False,self) 

109 self.guiobject.set_pildevice(self.pildevice) 

110 

111 self.cBut.config_changed_signal.connect(self.do_tabconfig_changed) 

112# 

113# handle changes of tab configuration 

114# 

115 def do_tabconfig_changed(self): 

116 param= self.cBut.get_changed_option_name() 

117# 

118# change local config parameters 

119# 

120 if param=="showidy": 

121 self.showIdy= PILCONFIG.get(self.name,"showidy") 

122 self.pildevice.set_show_idy(self.showIdy) 

123 self.pildevice2.set_show_idy(self.showIdy) 

124 elif param=="displaymode": 

125 self.displayMode= PILCONFIG.get(self.name,"displaymode") 

126 self.pildevice.set_displayMode(self.displayMode) 

127 self.pildevice2.set_displayMode(self.displayMode) 

128 elif param=="logmode": 

129 self.logMode= PILCONFIG.get(self.name,"logmode") 

130 self.pildevice.setlocked(True) 

131 self.pildevice.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode == LOG_OUTBOUND)) 

132 self.pildevice.setlocked(False) 

133 self.pildevice2.setlocked(True) 

134 self.pildevice2.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode == LOG_INBOUND)) 

135 self.pildevice2.setlocked(False) 

136 super().do_tabconfig_changed() 

137 

138 def enable(self): 

139 super().enable() 

140 self.parent.commthread.register(self.pildevice,self.name) 

141 self.pildevice.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode == LOG_OUTBOUND)) 

142 self.pildevice.set_show_idy(self.showIdy) 

143 self.pildevice.set_displayMode(self.displayMode) 

144 if self.logging: 

145 self.tagButton.setEnabled(True) 

146 

147 def post_enable(self): 

148 self.parent.commthread.register(self.pildevice2,self.name) 

149 self.pildevice2.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode== LOG_INBOUND)) 

150 self.pildevice2.set_show_idy(self.showIdy) 

151 self.pildevice2.set_displayMode(self.displayMode) 

152 

153 def disable(self): 

154 super().disable() 

155 

156 def do_cbActive(self): 

157 self.active= self.cbActive.isChecked() 

158 PILCONFIG.put(self.name,"active",self.active) 

159 self.pildevice.setlocked(True) 

160 self.pildevice.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode == LOG_OUTBOUND)) 

161 self.pildevice.setlocked(False) 

162 self.pildevice2.setlocked(True) 

163 self.pildevice2.setactive(PILCONFIG.get(self.name,"active") and not (self.logMode == LOG_INBOUND)) 

164 self.pildevice2.setlocked(False) 

165 

166 try: 

167 self.toggle_active() 

168 except AttributeError: 

169 pass 

170 return 

171# 

172# set tag button active/inactive 

173# 

174 def do_cbLogging(self): 

175 super().do_cbLogging() 

176 if self.logging: 

177 self.tagButton.setEnabled(True) 

178 else: 

179 self.tagButton.setEnabled(False) 

180# 

181# exec tag button, because we may write it asynchronous pause the thread 

182# 

183 def do_tagbutton(self): 

184 text,okPressed=QtWidgets.QInputDialog.getText(self,"Tag Logfile","Logfile tag",QtWidgets.QLineEdit.Normal,"") 

185 if okPressed and text != "": 

186 if self.parent.commthread is not None: 

187 if self.parent.commthread.isRunning(): 

188 self.parent.commthread.halt() 

189# 

190# all errors that might occur during log write are handled from the 

191# cbLogging methods, we do not need to catch errors 

192# 

193 self.cbLogging.logWrite("\n") 

194 self.cbLogging.logWrite(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) 

195 self.cbLogging.logWrite(" ** ") 

196 self.cbLogging.logWrite(text) 

197 self.cbLogging.logWrite("\n") 

198 if self.parent.commthread is not None: 

199 self.parent.commthread.resume() 

200# 

201# 

202# forward character to the terminal frontend widget and do logging 

203# 

204 def out_scope(self,s): 

205 l=len(s) 

206 if self.scope_charpos+l>=self.guiobject.get_cols() : 

207 self.guiobject.out_terminal(0x0D) 

208 self.guiobject.out_terminal(0x0A) 

209 self.cbLogging.logWrite("\n") 

210 self.cbLogging.logFlush() 

211 self.scope_charpos=0 

212 for i in range(0,len(s)): 

213 self.guiobject.out_terminal(ord(s[i])) 

214 self.cbLogging.logWrite(s) 

215 self.scope_charpos+=l 

216# 

217# HP-IL scope class ----------------------------------------------------------- 

218# 

219# Changelog 

220# 06.10.2015 jsi: 

221# - class statement syntax update 

222# 21.11.2015 jsi: 

223# - removed SSRQ/CSRQ approach 

224# - introduced show IDY frames option 

225# 29.11.2015 jsi: 

226# - introduced device lock 

227# 07.02.2016 jsi 

228# - refactored and merged new Ildev base class of Christoph Giesselink 

229# 28.04.2016 jsi: 

230# - introduced inbound parameter, if True use uppercase letters if False use loweercase 

231# 09.08.2017 jsi: 

232# - register_callback_output implemented (from base class) 

233# 14.09.2017 jsi 

234# - refactoring 

235 

236class cls_pilscope(cls_pildevbase): 

237 

238 def __init__ (self, inbound,parent): 

239 super().__init__() 

240 self.__inbound__= inbound 

241 self.__mnemo__= ["DAB", "DSR", "END", "ESR", "CMD", "RDY", "IDY", "ISR"] 

242 self.__scmd0__= ["NUL", "GTL", "???", "???", "SDC", "PPD", "???", "???", 

243 "GET", "???", "???", "???", "???", "???", "???", "ELN", 

244 "NOP", "LLO", "???", "???", "DCL", "PPU", "???", "???", 

245 "EAR", "???", "???", "???", "???", "???", "???", "???" ] 

246 self.__scmd9__= ["IFC", "???", "REN", "NRE", "???", "???", "???", "???", 

247 "???", "???", "AAU", "LPD", "???", "???", "???", "???"] 

248 self.__show_idy__= False 

249 self.__displayMode__= DISPLAY_MNEMONIC 

250 self.__parent__= parent 

251 

252# 

253# public ------- 

254# 

255 

256 def set_show_idy(self,flag): 

257 self.__show_idy__= flag 

258 

259 def set_displayMode(self,flag): 

260 self.__displayMode__= flag 

261# 

262# public (overloaded) ------- 

263# 

264# convert frame to readable text and call the parent method out_scope 

265# 

266 def process (self,frame): 

267 if not self.__isactive__: 

268 return(frame) 

269# 

270# ignore IDY frames 

271# 

272 if ((frame & 0x700) == 0x600) and not self.__show_idy__: 

273 return (frame) 

274 

275 n= frame & 255 

276 s= "{:3s} {:02X}".format(self.__mnemo__[frame // 256], n) 

277 

278# 

279# CMD 

280# 

281 if (frame & 0x700) == 0x400 : 

282 t= n // 32 

283 

284 if t == 0: 

285 s= self.__scmd0__[n & 31 ] 

286 elif t == 1: 

287 if (n & 31) == 31: 

288 s="UNL" 

289 else: 

290 s= "LAD {:02X}".format( n & 31) 

291 elif t == 2: 

292 if (n & 31) == 31: 

293 s="UNT" 

294 else: 

295 s= "TAD {:02X}".format( n & 31) 

296 elif t == 3: 

297 s= "SAD {:02X}".format( n & 31) 

298 elif t == 4: 

299 if (n & 31) < 16: 

300 s= "PPE {:02X}".format( n & 31) 

301 else: 

302 s= self.__scmd9__[n & 15] 

303 elif t == 5: 

304 s= "DDL {:02X}".format( n & 31) 

305 elif t == 6: 

306 s= "DDT {:02X}".format( n & 31) 

307 if s[0] =="?": 

308 s="CMD {:02x}".format(n) 

309 else: 

310# 

311# RDY 

312# 

313 if (frame & 0x700) == 0x500: 

314 if n < 128: 

315 if n == 0: 

316 s= "RFC" 

317 elif n == 64: 

318 s= "ETO" 

319 elif n == 65: 

320 s= "ETE" 

321 elif n == 66: 

322 s= "NRD" 

323 elif n == 96: 

324 s= "SDA" 

325 elif n == 97: 

326 s= "SST" 

327 elif n== 98: 

328 s = "SDI" 

329 elif n == 99: 

330 s = "SAI" 

331 elif n == 100: 

332 s = "TCT" 

333 else: 

334 s = "RDY {:2X}".format(n) 

335 else: 

336 t= n // 32 

337 if t == 4: 

338 s = "AAD {:2X}".format(n & 31) 

339 elif t == 5: 

340 s = "AEP {:2X}".format(n & 31) 

341 elif t == 6: 

342 s = "AES {:2X}".format(n & 31) 

343 elif t == 7: 

344 s = "AMP {:2X}".format(n & 31) 

345 else: 

346 s = "RDY {:2X}".format(n) 

347 

348# 

349# inbound frames are lowercase, outbound frames are uppercase 

350# 

351 if self.__displayMode__== DISPLAY_MNEMONIC: 

352 s="{:6s} ".format(s) 

353 elif self.__displayMode__== DISPLAY_HEX: 

354 s="{:03X} ".format(frame) 

355 elif self.__displayMode__== DISPLAY_BOTH: 

356 s="{:6s} ({:03X}) ".format(s,frame) 

357 if not self.__inbound__: 

358 s= s.lower() 

359 self.__access_lock__.acquire() 

360 locked= self.__islocked__ 

361 self.__access_lock__.release() 

362 if not locked: 

363 self.__parent__.out_scope(s) 

364 return (frame)