-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
7 changed files
with
730 additions
and
722 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
#!/usr/bin/env python | ||
|
||
#============================================================================= | ||
# QCalc programmer's Calculator | ||
# Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. | ||
|
@@ -23,101 +25,113 @@ | |
# <[email protected]> | ||
#============================================================================= | ||
## | ||
# @date Last updated on: 2022-01-27 | ||
# @version Last updated for version: 7.0.0 | ||
# @date Last updated on: 2023-12-18 | ||
# @version Last updated for version: 7.3.2 | ||
# | ||
# @file | ||
# @brief QCalc programmer's Calculator | ||
# @ingroup qtools | ||
|
||
# pylint: disable=broad-except | ||
# pylint: disable=eval-used | ||
|
||
|
||
''' | ||
"qcalc" is a powerful, cross-platform calculator specifically designed for | ||
embedded systems programmers. The calculator accepts whole expressions in | ||
the **C-syntax** and displays results simultaneously in decimal, hexadecimal, | ||
and binary without the need to explicitly convert the result to these bases. | ||
''' | ||
|
||
import os | ||
import sys | ||
import traceback | ||
|
||
from math import * | ||
from platform import python_version | ||
from sys import argv | ||
|
||
# NOTE: the following wildcard import from math is needed | ||
# for user expressions. | ||
# | ||
# pylint: disable=wildcard-import | ||
# pylint: disable=unused-wildcard-import | ||
# pylint: disable=redefined-builtin | ||
from math import * | ||
|
||
# current version of QCalc | ||
VERSION = 732 | ||
|
||
# the 'ans' global variable | ||
ans = 0 | ||
|
||
class QCalc: | ||
## current version of QCalc | ||
VERSION = 700 | ||
|
||
@staticmethod | ||
def _print(result): | ||
# the 'ans' global variable | ||
global ans | ||
ans = result | ||
|
||
if isinstance(ans, int): | ||
# outside the 64-bit range? | ||
if ans < -0xFFFFFFFFFFFFFFFF or 0xFFFFFFFFFFFFFFFF < ans: | ||
print("\x1b[41m\x1b[1;37m! out of range\x1b[0m") | ||
return | ||
|
||
#inside the 32-bit range? | ||
if -0xFFFFFFFF < ans and ans <= 0xFFFFFFFF: | ||
# use 32-bit unsigned arithmetic... | ||
u32 = ans & 0xFFFFFFFF | ||
u16_0 = u32 & 0xFFFF | ||
u16_1 = (u32 >> 16) & 0xFFFF | ||
u8_0 = u32 & 0xFF | ||
u8_1 = (u32 >> 8) & 0xFF | ||
u8_2 = (u32 >> 16) & 0xFF | ||
u8_3 = (u32 >> 24) & 0xFF | ||
print("= {0:d} |".format(ans), | ||
"0x{0:04X}'{1:04X} |".format(u16_1, u16_0), | ||
"0b{0:08b}'{1:08b}'{2:08b}'{3:08b}".format( | ||
u8_3, u8_2, u8_1, u8_0)) | ||
else: | ||
# use 64-bit unsigned arithmetic... | ||
u64 = ans & 0xFFFFFFFFFFFFFFFF | ||
u16_0 = u64 & 0xFFFF | ||
u16_1 = (u64 >> 16) & 0xFFFF | ||
u16_2 = (u64 >> 32) & 0xFFFF | ||
u16_3 = (u64 >> 48) & 0xFFFF | ||
u8_0 = u64 & 0xFF | ||
u8_1 = (u64 >> 8) & 0xFF | ||
u8_2 = (u64 >> 16) & 0xFF | ||
u8_3 = (u64 >> 24) & 0xFF | ||
u8_4 = (u64 >> 32) & 0xFF | ||
u8_5 = (u64 >> 40) & 0xFF | ||
u8_6 = (u64 >> 48) & 0xFF | ||
u8_7 = (u64 >> 56) & 0xFF | ||
print("= {0:d} |".format(ans), | ||
"0x{0:04X}'{1:04X}'{2:04X}'{3:04X}".format( | ||
u16_3, u16_2, u16_1, u16_0)) | ||
print("= 0b{0:08b}'{1:08b}'{2:08b}'{3:08b}" | ||
"'{4:08b}'{5:08b}'{6:08b}'{7:08b}".format( | ||
u8_7, u8_6, u8_5, u8_4, u8_3, u8_2, u8_1, u8_0)) | ||
ans = {} | ||
|
||
def display(result): | ||
''' | ||
Display result of computation in decimal, hexadecimal, and binary. | ||
Also, handle the 32-bit and 64-bit cases. | ||
''' | ||
|
||
# pylint: disable=global-statement | ||
global ans | ||
ans = result | ||
|
||
if isinstance(ans, int): | ||
# outside the 64-bit range? | ||
if ans < -0xFFFFFFFFFFFFFFFF or 0xFFFFFFFFFFFFFFFF < ans: | ||
print("\x1b[41m\x1b[1;37m! out of range\x1b[0m") | ||
return | ||
|
||
#inside the 32-bit range? | ||
if -0xFFFFFFFF < ans <= 0xFFFFFFFF: | ||
# use 32-bit unsigned arithmetic... | ||
u32 = ans & 0xFFFFFFFF | ||
u16_0 = u32 & 0xFFFF | ||
u16_1 = (u32 >> 16) & 0xFFFF | ||
u8_0 = u32 & 0xFF | ||
u8_1 = (u32 >> 8) & 0xFF | ||
u8_2 = (u32 >> 16) & 0xFF | ||
u8_3 = (u32 >> 24) & 0xFF | ||
print(f"= {ans:d} |", | ||
f"0x{u16_1:04X}'{u16_0:04X} |", | ||
f"0b{u8_3:08b}'{u8_2:08b}'{u8_1:08b}'{u8_0:08b}", end="") | ||
else: | ||
print("=", ans) | ||
# use 64-bit unsigned arithmetic... | ||
u64 = ans & 0xFFFFFFFFFFFFFFFF | ||
u16_0 = u64 & 0xFFFF | ||
u16_1 = (u64 >> 16) & 0xFFFF | ||
u16_2 = (u64 >> 32) & 0xFFFF | ||
u16_3 = (u64 >> 48) & 0xFFFF | ||
u8_0 = u64 & 0xFF | ||
u8_1 = (u64 >> 8) & 0xFF | ||
u8_2 = (u64 >> 16) & 0xFF | ||
u8_3 = (u64 >> 24) & 0xFF | ||
u8_4 = (u64 >> 32) & 0xFF | ||
u8_5 = (u64 >> 40) & 0xFF | ||
u8_6 = (u64 >> 48) & 0xFF | ||
u8_7 = (u64 >> 56) & 0xFF | ||
print(f"= {ans:d} |", | ||
f"0x{u16_3:04X}'{u16_2:04X}'{u16_1:04X}'{u16_0:04X}") | ||
print(f"= 0b{u8_7:08b}'{u8_6:08b}'{u8_5:08b}'{u8_4:08b}"\ | ||
f"'{u8_3:08b}'{u8_2:08b}'{u8_1:08b}'{u8_0:08b}", end="") | ||
else: | ||
print("=", ans) | ||
|
||
#============================================================================= | ||
# main entry point to QCalc | ||
def main(): | ||
if os.name == "nt": | ||
os.system("color") | ||
|
||
print("QCalc Programmer's Calculator {0:d}.{1:d}.{2:d} " \ | ||
"running on Python {3}".format( | ||
QCalc.VERSION//100, | ||
(QCalc.VERSION//10) % 10, | ||
QCalc.VERSION % 10, | ||
python_version())) | ||
print("(c) 2005-2022 Quantum Leaps, www.state-machine.com\n") | ||
|
||
''' | ||
Main entry point to QCalc. Process command-line parameters | ||
and handle separately "batch" and "interactive" modes. | ||
''' | ||
# "batch mode": expression provided in command-line arguments | ||
if len(argv) > 1: | ||
expr = "".join(argv[1:]) | ||
if len(sys.argv) > 1: | ||
expr = "".join(sys.argv[1:]) | ||
print(expr) | ||
try: | ||
result = eval(expr) | ||
except: | ||
except Exception: | ||
traceback.print_exc(2) | ||
else: | ||
QCalc._print(result) | ||
display(result) | ||
return | ||
|
||
# "interactive mode": expressions provided as user input | ||
|
@@ -126,16 +140,27 @@ def main(): | |
if expr: | ||
try: | ||
result = eval(expr) | ||
except: | ||
except Exception: | ||
traceback.print_exc(2) | ||
else: | ||
print("\x1b[47m\x1b[30m", end = "") | ||
QCalc._print(result) | ||
print("\x1b[0m", end = "") | ||
display(result) | ||
print("\x1b[0m") | ||
else: | ||
break | ||
|
||
|
||
#============================================================================= | ||
if __name__ == "__main__": | ||
main() | ||
if os.name == "nt": | ||
os.system("color") | ||
|
||
print(f"\nQCalc programmer's calculator "\ | ||
f"{VERSION//100}.{(VERSION//10) % 10}."\ | ||
f"{VERSION % 10} running on Python {python_version()}") | ||
print("Copyright (c) 2005-2023 Quantum Leaps, www.state-machine.com") | ||
if sys.version_info >= (3,6): | ||
main() | ||
else: | ||
print("\nERROR: QCalc requires Python 3.6 or newer") | ||
sys.exit(-1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
|
||
setup( | ||
name="qcalc", | ||
version="7.0.0", | ||
version="7.3.2", | ||
author="Quantum Leaps", | ||
author_email="[email protected]", | ||
description="qcalc programmer's calculator", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#!/usr/bin/env python | ||
|
||
#============================================================================= | ||
# QUTest Python scripting support | ||
# qspy_exit utility | ||
# Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. | ||
# | ||
# SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial | ||
|
@@ -22,31 +24,27 @@ | |
# <www.state-machine.com> | ||
# <[email protected]> | ||
#============================================================================= | ||
## | ||
# @date Last updated on: 2023-12-13 | ||
# @version Last updated for version: 7.3.1 | ||
# | ||
# @file | ||
# @brief QUTest Python scripting support (implementation) | ||
# @ingroup qutest | ||
|
||
# pylint: disable=missing-module-docstring, | ||
# pylint: disable=missing-class-docstring, | ||
# pylint: disable=missing-function-docstring | ||
# pylint: disable=broad-except | ||
|
||
from platform import python_version | ||
|
||
import argparse | ||
import socket | ||
import struct | ||
import sys | ||
import os | ||
if os.name == "nt": | ||
import msvcrt | ||
else: | ||
import select | ||
|
||
from platform import python_version | ||
|
||
#============================================================================= | ||
# Helper class for communication with the QSpy front-end | ||
# | ||
class QSpy: | ||
VERSION = 731 | ||
|
||
# public class constants | ||
VERSION = 732 | ||
TIMEOUT = 1.000 # timeout value [seconds] | ||
|
||
# private class variables... | ||
_sock = None | ||
|
@@ -55,9 +53,6 @@ class QSpy: | |
_host_udp = ["localhost", 7701] # list, to be converted to a tuple | ||
_local_port = 0 # let the OS decide the best local port | ||
|
||
# timeout value [seconds] | ||
_TOUT = 1.000 | ||
|
||
# packets to QSpy only... | ||
_QSPY_ATTACH = 128 | ||
_QSPY_DETACH = 129 | ||
|
@@ -69,68 +64,55 @@ class QSpy: | |
_QSPY_CLEAR_SCREEN = 140 | ||
_QSPY_SHOW_NOTE = 141 | ||
|
||
# packets to QSpy to be "massaged" and forwarded to the Target... | ||
_QSPY_SEND_EVENT = 135 | ||
_QSPY_SEND_AO_FILTER = 136 | ||
_QSPY_SEND_CURR_OBJ = 137 | ||
_QSPY_SEND_COMMAND = 138 | ||
_QSPY_SEND_TEST_PROBE = 139 | ||
|
||
@staticmethod | ||
def _init(): | ||
# Create socket | ||
QSpy._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
QSpy._sock.settimeout(QSpy._TOUT) # timeout for blocking socket | ||
QSpy._sock.settimeout(QSpy.TIMEOUT) # timeout for blocking socket | ||
#bufsize = QSpy._sock.getsockopt(socket.SOL_UDP, socket.SO_RCVBUF) | ||
#print("SO_RCVBUF ", bufsize) | ||
try: | ||
QSpy._sock.bind(("0.0.0.0", QSpy._local_port)) | ||
#print("bind: ", ("0.0.0.0", QSpy._local_port)) | ||
except: | ||
messagebox.showerror("UDP Socket Error", | ||
"Can't bind the UDP socket\nto the specified local_host") | ||
QSpyView._gui.destroy() | ||
return -1 | ||
except Exception: | ||
print("UDP Socket Error"\ | ||
"Can't bind the UDP socket\nto the specified local_host") | ||
sys.exit(-1) | ||
return 0 | ||
|
||
@staticmethod | ||
def _sendTo(packet, str=None): | ||
def send_to(packet, payload=None): | ||
tx_packet = bytearray([QSpy._tx_seq]) | ||
tx_packet.extend(packet) | ||
if str is not None: | ||
tx_packet.extend(bytes(str, "utf-8")) | ||
if payload is not None: | ||
tx_packet.extend(bytes(payload, "utf-8")) | ||
tx_packet.extend(b"\0") # zero-terminate | ||
QSpy._sock.sendto(tx_packet, QSpy._host_udp) | ||
QSpy._tx_seq = (QSpy._tx_seq + 1) & 0xFF | ||
#print("sendTo", QSpy._tx_seq) | ||
|
||
#============================================================================= | ||
# main entry point to QUTest | ||
# main entry point to qspy_exit | ||
def main(): | ||
# pylint: disable=protected-access | ||
|
||
# parse command-line arguments... | ||
parser = argparse.ArgumentParser( | ||
prog="python qspy_exit.py", | ||
description="QSPY-exit", | ||
epilog="More info: https://www.state-machine.com/qspy.html#qspy_exit") | ||
parser.add_argument('-v', '--version', | ||
action='version', | ||
version="QSPY-exit %d.%d.%d on Python %s"%( | ||
QSpy.VERSION//100, (QSpy.VERSION//10) % 10, | ||
QSpy.VERSION % 10, | ||
python_version()), | ||
version=f"QSPY-exit {QSpy.VERSION//100}."\ | ||
f"{(QSpy.VERSION//10) % 10}.{QSpy.VERSION % 10} "\ | ||
f"on Python {python_version()}", | ||
help='Display QSPY-exit version') | ||
|
||
parser.add_argument('-q', '--qspy', nargs='?', default='', const='', | ||
help="optional qspy host, [:ud_port]") | ||
args = parser.parse_args() | ||
#print(args) | ||
|
||
print("\nQSPY-exit %d.%d.%d running on Python %s"%( | ||
QSpy.VERSION//100, | ||
(QSpy.VERSION//10) % 10, | ||
QSpy.VERSION % 10, python_version())) | ||
print("Copyright (c) 2005-2023 Quantum Leaps, www.state-machine.com") | ||
|
||
# process command-line argumens... | ||
if args.qspy != '': | ||
qspy_conf = args.qspy.split(":") | ||
|
@@ -150,10 +132,18 @@ def main(): | |
if err: | ||
return sys.exit(err) | ||
|
||
QSpy._sendTo(struct.pack("<BB", QSpy._QSPY_DETACH, 1)) | ||
QSpy.send_to(struct.pack("<BB", QSpy._QSPY_DETACH, 1)) | ||
|
||
return 0 # report to the caller (e.g., make) | ||
|
||
#============================================================================= | ||
if __name__ == "__main__": | ||
main() | ||
print(f"\nQSPY-exit "\ | ||
f"{QSpy.VERSION//100}.{(QSpy.VERSION//10) % 10}."\ | ||
f"{QSpy.VERSION % 10} running on Python {python_version()}") | ||
print("Copyright (c) 2005-2023 Quantum Leaps, www.state-machine.com") | ||
if sys.version_info >= (3,6): | ||
main() | ||
else: | ||
print("\nERROR: QSPY-exit requires Python 3.6 or newer") | ||
sys.exit(-1) |
Oops, something went wrong.