diff --git a/README.md b/README.md
index 8882ceb..fbe3489 100644
--- a/README.md
+++ b/README.md
@@ -160,25 +160,32 @@ These changes where made intentionally to make further development easier. See t
been tested:
### Programming Stations
-| Control | Software |
-|-------------|----------------|
-| TNC640 | 340595 08 SP1 |
-| TNC640 | 340595 10 SP2 |
-| TNC640 | 340595 11 SP1 |
-| TNC640 | 340595 11 SP4 |
-| iTNC530 | 606425 04 SP20 |
-| iTNC530 | 340494 08 SP2 |
-| CNCpilot640 | 1230521 03 SP1 |
-| TNC7 | 817625 17 |
+| Control | Software | Notes |
+|-----------------|----------------|-------|
+| TNC320 | 340554 04 SP1 | 1 |
+| TNC640 | 340594 01 | |
+| TNC640 | 340595 08 SP1 | |
+| TNC640 | 340595 10 SP2 | |
+| TNC640 | 340595 11 SP1 | |
+| TNC640 | 340595 11 SP4 | |
+| iTNC530 | 606425 04 SP20 | |
+| iTNC530 | 340494 08 SP2 | |
+| MANUALplus620 | 634130 02 SP7 | |
+| CNCpilot640 | 1230521 03 SP1 | |
+| TNC7 | 817625 17 | |
+| MillPlusIT V600 | 538956 03 SP15 | 1, 2 |
+
+1) some tests are failing and have not been analysed yet (screendump and rw_machine_parameter)
+2) this control is not officially supported by any other Heidenhain tool but seems to be at least somewhat compatible
### Machines
-| Control | Software |
-|-------------|----------------|
-| TNC620 | 817605 04 SP1 |
-| TNC640 | 340595 08 SP1 |
-| iTNC530 | 340480 14 SP4 |
-| iTNC530 | 606420 02 SP14 |
-| iTNC530 | 606420 02 SP3 |
+| Control | Software | Notes |
+|-----------------|----------------|-------|
+| TNC620 | 817605 04 SP1 | |
+| TNC640 | 340595 08 SP1 | |
+| iTNC530 | 340480 14 SP4 | |
+| iTNC530 | 606420 02 SP14 | |
+| iTNC530 | 606420 02 SP3 | |
If you have tested it on one of your machines with a different software version, please let us know!
diff --git a/pyLSV2/client.py b/pyLSV2/client.py
index d807725..064c2ca 100644
--- a/pyLSV2/client.py
+++ b/pyLSV2/client.py
@@ -70,7 +70,7 @@ def versions(self) -> ld.VersionInfo:
"""version information of the connected control"""
return self._versions
- @property
+ @property
def parameters(self) -> ld.SystemParameters:
"""system parameters of the connected control"""
return self._sys_par
diff --git a/pyLSV2/const.py b/pyLSV2/const.py
index 6326a89..6402089 100644
--- a/pyLSV2/const.py
+++ b/pyLSV2/const.py
@@ -95,6 +95,8 @@ class ControlType(Enum):
TNC7 = 5
"""the TNC7 is the new control that behaves just a bit different again so we need a special case for it"""
+ MILLPLUS = 6
+ """the MILLPlusIT V600 is officially"""
class Login(str, Enum):
"""Enum for the different login roles"""
diff --git a/pyLSV2/dat_cls.py b/pyLSV2/dat_cls.py
index bcf7c8e..7243121 100644
--- a/pyLSV2/dat_cls.py
+++ b/pyLSV2/dat_cls.py
@@ -8,9 +8,11 @@
from datetime import datetime
import struct
+import re
from typing import List
from .const import ControlType, LSV2StatusCode, ChannelType
+from .err import LSV2DataException
class VersionInfo:
@@ -27,6 +29,9 @@ def __init__(self):
self.id_number = ""
self.release = ""
+ self._ncsw_reg = re.compile(r"(?P\d{5})(?P\d)(?:[ -])(?P\d+)(?: (?P.*))?")
+
+
def __str__(self) -> str:
return "%s / %s" % (self.control, self.nc_sw)
@@ -57,10 +62,14 @@ def control(self, value: str):
self.type = ControlType.MILL_NEW
elif value.startswith("TNC128"):
self.type = ControlType.MILL_NEW
+ elif value.startswith("MANUALPLUS"):
+ self.type = ControlType.LATHE_NEW
elif value.startswith("CNCPILOT640"):
self.type = ControlType.LATHE_NEW
elif value.startswith("TNC7"):
self.type = ControlType.TNC7
+ elif value.startswith("MILLPLUS"):
+ self.type = ControlType.MILLPLUS
else:
self.type = ControlType.UNKNOWN
@@ -144,6 +153,14 @@ def is_pilot(self) -> bool:
"""return ``True`` if control is a CNCPILOT640"""
return self._control_type == ControlType.LATHE_NEW
+ def is_manualplus(self) -> bool:
+ """return ``True`` if control is a MANUALplus620"""
+ return self._control_type == ControlType.LATHE_NEW
+
+ def is_millplus(self) -> bool:
+ """return ``True`` if control is a MillPlus"""
+ return self._control_type == ControlType.MILLPLUS
+
def is_tnc7(self) -> bool:
"""return ```True``` if control is a TNC7"""
return self._control_type == ControlType.TNC7
@@ -151,24 +168,38 @@ def is_tnc7(self) -> bool:
@property
def nc_sw_base(self) -> int:
"""base nc software as integer"""
- return int(self.nc_sw[:5]) * 10
+ result = self._ncsw_reg.fullmatch(self.nc_sw)
+ if result is None or "base" not in result.groupdict():
+ raise LSV2DataException("could not parse nc software base version from '%s'" % self.nc_sw)
+ return int(result.group("base")) * 10
@property
def nc_sw_type(self) -> int:
"""nc software type"""
- return int(self.nc_sw[5:6])
+ result = self._ncsw_reg.fullmatch(self.nc_sw)
+ if result is None or "type" not in result.groupdict():
+ raise LSV2DataException("could not parse nc software type from '%s'" % self.nc_sw)
+ return int(result.group("type"))
@property
def nc_sw_version(self) -> int:
"""nc software version number"""
- return int(self.nc_sw[7:9])
+ result = self._ncsw_reg.fullmatch(self.nc_sw)
+ if result is None or "version" not in result.groupdict():
+ raise LSV2DataException("could not parse nc software version from '%s'" % self.nc_sw)
+ return int(result.group("version"))
@property
def nc_sw_service_pack(self) -> int:
"""service pack number"""
- if len(self.nc_sw) > 9:
- return int(self.nc_sw[12:])
- return 0
+ result = self._ncsw_reg.fullmatch(self.nc_sw)
+ if result is None:
+ raise LSV2DataException("could not parse service pack from '%s'" % self.nc_sw)
+ if result.group("sp") is None:
+ return 0
+ sp_str = result.group("sp").lower()
+ sp_str = sp_str.lstrip("sp")
+ return int(sp_str)
class SystemParameters:
diff --git a/pyLSV2/scripts/demo.py b/pyLSV2/scripts/demo.py
index 3a4df18..e30e37d 100644
--- a/pyLSV2/scripts/demo.py
+++ b/pyLSV2/scripts/demo.py
@@ -60,7 +60,12 @@ def comprehensive_demo():
)
)
- print("# Time and date: {:}".format(con.get_remote_datetime()))
+ if con.versions.nc_sw_type == 4:
+ print("# Reading time and date on a windows programming station is not supported")
+ elif con.versions.nc_sw_base == 538950:
+ print("# Reading time and date on a windows MILLplusIT programming station is not supported")
+ else:
+ print("# Time and date: {:}".format(con.get_remote_datetime()))
# read error messages via LSV2, works only on iTNC controls
print("# read error messages, only available on some iTNC530 versions")
diff --git a/tests/test_file_functions.py b/tests/test_file_functions.py
index 102413c..a6a92c4 100644
--- a/tests/test_file_functions.py
+++ b/tests/test_file_functions.py
@@ -14,6 +14,8 @@ def test_read_info(address: str, timeout: float):
mdi_path = "TNC:\\$MDI.H"
elif lsv2.versions.is_pilot():
mdi_path = "TNC:\\nc_prog\\ncps\\PGM01.nc"
+ elif lsv2.versions.is_millplus():
+ mdi_path = "TNC:\\mdi\\mdi.pm"
else:
mdi_path = "TNC:\\nc_prog\\$mdi.h"
@@ -65,6 +67,9 @@ def test_remote_file_functions(address: str, timeout: float):
elif lsv2.versions.is_pilot():
mdi_dir = "TNC:\\nc_prog\\ncps\\"
mdi_name = "PGM01.nc"
+ elif lsv2.versions.is_millplus():
+ mdi_dir = "TNC:\\mdi\\"
+ mdi_name = "mdi.pm"
else:
mdi_dir = "TNC:\\nc_prog\\"
mdi_name = "$mdi.h"
@@ -113,6 +118,8 @@ def test_path_formating(address: str, timeout: float):
mdi_path = "TNC:/$MDI.H"
elif lsv2.versions.is_pilot():
mdi_path = "TNC:/nc_prog/ncps/PGM01.nc"
+ elif lsv2.versions.is_millplus():
+ mdi_path = "TNC:/mdi/mdi.pm"
else:
mdi_path = "TNC:/nc_prog/$mdi.h"
diff --git a/tests/test_transfer.py b/tests/test_transfer.py
index 0e40f19..b40efab 100644
--- a/tests/test_transfer.py
+++ b/tests/test_transfer.py
@@ -19,6 +19,9 @@ def test_file_recive(address: str, timeout: float):
elif lsv2.versions.is_pilot():
mdi_path = "TNC:/nc_prog/ncps/PGM01.nc"
tool_t_path = "TNC:/table/toolturn.htt"
+ elif lsv2.versions.is_millplus():
+ mdi_path = "TNC:/mdi/mdi.pm"
+ tool_t_path = "TNC:/table/tool.t"
else:
mdi_path = "TNC:/nc_prog/$mdi.h"
tool_t_path = "TNC:/table/tool.t"
@@ -121,6 +124,8 @@ def test_recive_with_path_formating(address: str, timeout: float):
mdi_path = "TNC:/$MDI.H"
elif lsv2.versions.is_pilot():
mdi_path = "TNC:/nc_prog/ncps/PGM01.nc"
+ elif lsv2.versions.is_millplus():
+ mdi_path = "TNC:/mdi/mdi.pm"
else:
mdi_path = "TNC:/nc_prog/$mdi.h"