Skip to content

Commit

Permalink
Merge branch 'split-core' into 'master'
Browse files Browse the repository at this point in the history
Split core functionality

See merge request sd/sdmay23-47!17

Former-commit-id: 1fe3885666dc20f62f8bfeb734b4059d18bf0504
  • Loading branch information
Corbeno committed Apr 20, 2023
2 parents 42af0bf + 4fa0d0a commit bc8703b
Show file tree
Hide file tree
Showing 2,895 changed files with 972,932 additions and 56,652 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*.pyc
*.csv
cli/__pycache__
venv/

# These directories are created when compile.sh is run
build
Expand All @@ -13,4 +14,5 @@ dist
data.txt

# Matlab file extensions
*.m
*.m
*.mat
1 change: 0 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ test:
script:
- python -m pip install -r requirements.txt
- python cli/testing/cli_test.py
- python cli/testing/speed_test.py

run:
script:
Expand Down
97 changes: 83 additions & 14 deletions cli/CLIWrapper.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import os
import pexpect
from sys import platform
from pexpect import popen_spawn
from threading import Thread
from waiting import wait
import json
import re
import csv
import sys
import time
import pandas

from main import CyDAQ_CLI

cli_tool = CyDAQ_CLI()

CLI_MAIN_FILE_NAME = "main.py"
INPUT_CHAR = ">"
NOT_CONNECTED = "Zybo not connected"
LOG_MAX_LENGTH = 10000

# Log file location for different OS's (development)
if platform == "win32":
DEFAULT_LOG_FILE = f"C:\\Temp\\cydaq_current_log.log"
else:
DEFAULT_LOG_FILE = f"/tmp/cydaq_current_log.log"

# Default timeout for all commands (in seconds). May be increased if some commands take longer
TIMEOUT = 10
TIMEOUT = 20


class CLI:
Expand All @@ -31,10 +41,26 @@ class CLI:
"""

def __init__(self):
self.log = ""
# Global Variables
self.running_ping_command = False
self.bb_log_thread = None
self.bb_log_mode = False
self.mocking = False

# Logging
self.log = ""
self.log_buffer = ""

# Remove existing file if it exists
if os.path.exists(DEFAULT_LOG_FILE):
try:
os.remove(DEFAULT_LOG_FILE)
except PermissionError:
print("Unable to delete log file!! ", DEFAULT_LOG_FILE)

# Create log file
self.logfile = open(DEFAULT_LOG_FILE, 'a+')
sys.stdout = self.logfile

# Run the CLI tool using the pexpect library just like a user would in the terminal
pythonCmd = "python3 "
Expand Down Expand Up @@ -99,7 +125,9 @@ def _send_command(self, command, wrapper_mode=True, force_async=False, **_):
self.running_command = False
raise cyDAQNotConnectedException

if command != "q" and command != "bb_start":
if command != "q" and command != "bb_start" and command != "bb_offset_inc" and command != "bb_offset_dec" and not re.search(
'bb_const, [0-9]*\.[0-9]+ [0-9]*\.[0-9]+ [0-9]*\.[0-9]+ [0-9]+', command) and not re.search(
'bb_set, [0-9]*\.[0-9]+', command):
# Wait for response
try:
self.p.expect(INPUT_CHAR)
Expand All @@ -117,11 +145,11 @@ def _send_command(self, command, wrapper_mode=True, force_async=False, **_):
response = response.decode()
response = response.strip()

self.log = response + "\n" + self.log
print(response)
if command != "bb_fetch_pos": # Can get a bit spammy
self.log = "Cmd: " + command + "\n" + self.log + "\n"
print(f"Cmd: {command}")
self.writeLog("response", response)
# print(response)
if command != "bb_fetch_pos": # Can get a bit spammy
self.writeLog("cmd", command)
# print(f"Cmd: {command}")
if wrapper_mode:
if command == "ping":
self.running_ping_command = False
Expand Down Expand Up @@ -163,7 +191,7 @@ def _parse_wrapper_mode_message(self, line):
return message
else:
raise CLIUnknownLogLevelException
print(line)
# print(line)
return ""

def _error_parser(self, message):
Expand All @@ -173,25 +201,33 @@ def _error_parser(self, message):
elif message == cli_tool.BALANCE_BEAM_NOT_CONNECTED:
self.stop_bb()
raise BalanceBeamNotConnectedException
elif message == "Error opening file!": # TODO make constant
raise cyDAQFileException("Error opening the file specified! Is it already open in another program?")
else:
raise CLIException(message)

def ping(self, **_):
"""Ping cyDAQ, returns the response time in microseconds or -1 if error"""
response = self._send_command("ping")
print("ping response: ", response)
# if response == "CyDAQ not connected": #TODO make constant
# return -1
try:
return int(''.join(filter(str.isdigit, response))) # type: ignore
except ValueError:
if response == "":
raise CLIException("Unable to connect to CyDAQ through wrapper. Is the CyDAQ on? "
"Is there another instance running/connected to the CyDAQ? "
"Is there another program using that com port?")
elif response == "Error sending config!":
pass # Do nothing since error is already handled
else:
raise CLIException("Unable to parse ping response. Response was: {}".format(response))

def close(self, **_):
"""Close the CLI tool"""
self._send_command("q")
self.logfile.close()

def clear_config(self, **_):
"""Clear the config to its default values"""
Expand All @@ -209,7 +245,11 @@ def get_config(self, **_):

def send_config_to_cydaq(self, **_):
"""Send the current configuration stored in the CLI to the cyDAQ"""
self._send_command("send")
response = self._send_command("send")
if response == "Config sent successfully!":
return True
elif response == "Error sending config!":
return False

def set_value(self, key, value, **_):
"""
Expand Down Expand Up @@ -256,26 +296,29 @@ def generate(self, **_):
def enable_mock(self, **_):
"""Enable CyDAQ serial connection mocking"""
self._send_command("mock, enable")
self.mocking = True

def disable_mock(self, **_):
"""Disable CyDAQ serial connection mocking"""
self._send_command("mock, disable")
self.mocking = False

def isMocking(self, **_):
"""Returns True if mocking a CyDAQ serial connection, False otherwise"""
response = self._send_command("mock, status")
return response == "True"
self.mocking = response == "True"
return self.mocking

### Balance Beam Wrapper Methods ###

def start_bb(self, **_):
def start_bb(self, kp=None, ki=None, kd=None, N=None, set=None, **_):
"""Start balance beam mode and live data streaming"""

# If a ping command is running, wait for it to finish
wait(lambda: not self.running_ping_command)

# Check if the balance beam is connected before retrieving data
response = self._send_command("bb_start")
response = self._send_command(f"bb_start, {kp} {ki} {kd} {N} {set}")
if not response == CyDAQ_CLI.BALANCE_BEAM_NOT_CONNECTED:
self.bb_log_mode = True
self.bb_log_thread = Thread(target=self.retrieve_bb_pos)
Expand Down Expand Up @@ -366,18 +409,34 @@ def readALotOfData(self, label, **_):
print("Total Lines: " + "{:,}".format(len(pandas.read_csv('lotsOfData.csv'))))
print("Lines Per Second: " + "{:,}".format(round(len(csvFile) / (stop - start))))

def writeLog(self, type, string, **_):
if type == "response":
self.logfile.write(f"{string}\n")
self.log_buffer = f"{string}\n{self.log_buffer}"
elif type == "cmd":
self.logfile.write(f"Cmd: {string}\n")
self.log_buffer = f"Cmd: {string}\n{self.log_buffer}"

def getLog(self, **_):
if self.log_buffer != "":
lines = self.log.splitlines()
if len(lines) > LOG_MAX_LENGTH:
lines = lines[0:LOG_MAX_LENGTH - len(self.log_buffer.splitlines())]
self.log = '\n'.join(lines)
self.log = f"{self.log_buffer}\n{self.log}"
self.log_buffer = ""
return self.log

def clearLog(self, **_):
self.log = ""

def convertMillis(self, millis, **_):
seconds = (millis / 1000) % 60
minutes = (millis / (1000 * 60)) % 60
hours = (millis / (1000 * 60 * 60)) % 24
return seconds, minutes, hours


class CLIException(Exception):
"""Generic exception raised for errors when using the CLI tool"""

Expand All @@ -396,10 +455,20 @@ def __init__(self):
super().__init__("CyDAQ is not connected properly!")


class cyDAQFileException(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)

def getMessage(self):
return self.message


class BalanceBeamNotConnectedException(Exception):
def __init__(self):
super().__init__("The Balance Beam is not connected to the CyDAQ!")


class CLICloseException(Exception):
"""Thrown when the CLI closes unexpectedly. The last message sent to the output should be included in this error. """

Expand Down
26 changes: 21 additions & 5 deletions cli/command_comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def recieve_acknowlege_zybo(self):
print('CyDAQ encountered error during configuration, contact ETG')
return False
else:
# self.__throw_exception('ack was not received')
self.__throw_exception('ack was not received')
print("'ack' was not received")
return False
else:
Expand Down Expand Up @@ -436,6 +436,17 @@ def send_start(self):
self.__throw_exception('Sending start failed')
return False

def send_stop_sampling(self):
self.ctrl_comm_obj.open(self.port)
if self.ctrl_comm_obj.isOpen() is True:
self.ctrl_comm_obj.write(sig_serial.START_BYTE.value.encode())
self.ctrl_comm_obj.write(struct.pack('!B', enum_commands.STOP_SAMPLING.value))
self.ctrl_comm_obj.write(sig_serial.END_BYTE.value.encode())

else:
self.__throw_exception('Sending start failed')
return False

def send_start_gen(self):
self.ctrl_comm_obj.open(self.port)
if self.ctrl_comm_obj.isOpen() is True:
Expand Down Expand Up @@ -520,6 +531,7 @@ def ping_zybo(self):
cnt = 0
while True:
if self.recieve_acknowlege_zybo():
print("ping ack recieved")
return True
elif cnt > 10:
return False
Expand Down Expand Up @@ -553,7 +565,7 @@ def is_mock_mode(self):

### Balance Beam Commands ###

def start_bb(self):
def start_bb(self, kp=None, ki=None, kd=None, N=None, set=None):
"""
Sends the start command to the CyDAQ
"""
Expand All @@ -570,9 +582,13 @@ def start_bb(self):
else:
self.__throw_exception('Starting balance beam mode failed')

# Set Default Values on Startup
self.update_constants(DEFAULT_KP, DEFAULT_KI, DEFAULT_KD, DEFAULT_N)
self.update_set(DEFAULT_SET)
# Set Default Values on Startup or Use Given Values
if not [x for x in (kp, ki, kd, N, set) if x is None]:
self.update_constants(kp, ki, kd, N)
self.update_set(N)
else:
self.update_constants(DEFAULT_KP, DEFAULT_KI, DEFAULT_KD, DEFAULT_N)
self.update_set(DEFAULT_SET)

def stop_bb(self):
"""
Expand Down
Loading

0 comments on commit bc8703b

Please sign in to comment.