├── .gitignore ├── LICENSE ├── README.md ├── constraints.txt ├── m700.py ├── requirements.txt └── test_m700.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mitsubishi-cnc-m700 2 | 三菱電機CNC M700シリーズとEZSocketを使って通信するPythonのサンプルです。 3 | 4 | Windows環境で、COMオブジェクトを利用することで動作します。 5 | 6 | 自身の環境で実装する際のヒントとしてお使い下さい。 7 | 8 | # 実装機能 9 | - DデバイスとMデバイスへの値の読み込みと書き込み 10 | - NCの状態やツール番号や回転数などの情報取得 11 | - NC内のディレクト検索とファイルの操作(read・write・delete) 12 | 13 | # 参考情報 14 | 15 | ## Windows環境で、以下の三菱CNC通信用ソフトウェア開発キットが必要です 16 | http://www.mitsubishielectric.co.jp/fa/download/software/detailsearch.do?mode=software&kisyu=/cnc&shiryoid=0000000030&lang=1&select=0&softid=1&infostatus=3_11_2&viewradio=0&viewstatus=&viewpos= 17 | 18 | ### 三菱CNC用通信ソフトウェア FCSB1224W000 リファレンスマニュアル 19 | http://www.mitsubishielectric.co.jp/fa/document/others/cnc/ib-1501208/IB-1501208.pdf 20 | 21 | ### COMへVARIANT型の引数をPythonから渡す方法 22 | http://docs.activestate.com/activepython/3.4/pywin32/html/com/win32com/HTML/variant.html 23 | https://mail.python.org/pipermail/python-win32/2012-October/012575.html 24 | 25 | ### pythoncom.VT_VARIANTの型一覧 26 | http://nullege.com/codes/search/pythoncom.VT_VARIANT 27 | 28 | 29 | # 使い方 30 | 31 | ``` 32 | # Open connection 33 | m700 = M700.get_connection('192.168.1.10:683') 34 | 35 | # NC内情報取得 36 | m700.get_drive_infomation() 37 | m700.get_run_status() 38 | m700.get_alerm() 39 | 40 | # Dデバイスへの操作 41 | m700.write_dev('M900', 1) 42 | m700.read_dev('M900') # -> 1 43 | 44 | # Mデバイスへの操作 45 | m700.write_dev('D200', 10) 46 | m700.read_dev('D200') # -> 10 47 | 48 | # 加工プログラムのファイルの操作(read・write・delete) 49 | drivenm = m700.get_drive_infomation() 50 | m700.write_file(drivenm + '¥PRG¥USER¥__TEST__.txt', b'TEST_WRITE') 51 | m700.read_file(drivenm + '¥PRG¥USER¥__TEST__.txt') 52 | m700.delete_file(drivenm + '¥PRG¥USER¥__TEST__.txt') 53 | 54 | # Close connection 55 | m700.close() 56 | ``` 57 | -------------------------------------------------------------------------------- /constraints.txt: -------------------------------------------------------------------------------- 1 | pywin32==224 2 | -------------------------------------------------------------------------------- /m700.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | ''' 3 | 三菱電機CNC M700シリーズとEZSocketを使って通信する。 4 | 通信対象はマシニングセンタ系三菱CNC M700/M700V/M70/M70V。 5 | ''' 6 | from enum import Enum 7 | import threading 8 | 9 | import pythoncom 10 | import win32com.client 11 | from win32com.client import VARIANT 12 | 13 | 14 | class M700(): 15 | 16 | #同一スレッド内で同一ホストの接続は同じインスタンスを使う 17 | #同一スレッドなのは、COMオブジェクトを別スレッドで共有するのが複雑なため 18 | __connections = {} 19 | @classmethod 20 | def get_connection(cls, host): 21 | key = str(threading.current_thread().ident) + "_" + host 22 | if key not in cls.__connections: 23 | cls.__connections[key] = M700(host) 24 | return cls.__connections[key] 25 | 26 | #1-255の一意の値管理 27 | __uno_list = [False]*255 28 | @classmethod 29 | def alloc_unitno(cls): 30 | '''EZSocketで未使用のユニット番号を返す。 31 | 32 | Returns: 33 | int: ユニット番号 34 | ''' 35 | for i,v in enumerate(cls.__uno_list): 36 | if v == False: 37 | cls.__uno_list[i] = True 38 | return i+1 39 | raise Exception("ユニット番号が255を超えました。同時接続数が多すぎます") 40 | 41 | @classmethod 42 | def release_unitno(cls, uno): 43 | cls.__uno_list[uno-1] = False 44 | 45 | # --- クラス内利用列挙体 --- 46 | 47 | class RunStatus(Enum): 48 | '''運転状態(valueはM700の返される値に対応している)''' 49 | NOT_AUTO_RUN = 0 50 | AUTO_RUN = 1 51 | 52 | class Position(Enum): 53 | '''X,Y,Z座標指定(valueはM700の返される値に対応している)''' 54 | X = 1 55 | Y = 2 56 | Z = 3 57 | 58 | class ProgramType(Enum): 59 | '''メインorサブプログラム(valueはM700の返される値に対応している)''' 60 | MAIN = 0 61 | SUB = 1 62 | 63 | class NCProgramFileOpenMode(Enum): 64 | '''NC内のプログラムファイルを開く際にしているするモード''' 65 | READ = 1 66 | WRITE = 2 67 | OVER_WRITE = 3 68 | 69 | __ip = None 70 | __port = None 71 | __isopen = False 72 | __ezcom = None 73 | __lock = threading.RLock() 74 | 75 | def __init__(self, host): 76 | ''' 77 | Args: 78 | host: IPアドレス:ポート番号 79 | ''' 80 | pythoncom.CoInitialize() # 複数スレッドで実行する際は、COMオブジェクトの初期化が必要 81 | self.__ip, self.__port = host.split(':') 82 | 83 | def __str__(self): 84 | return self.__ip + ":" + self.__port + " " + ("Open" if self.__isopen else "Close") 85 | 86 | def __open(self): 87 | '''引数として与えられたIPとユニット番号に対してコネクションを開く。 88 | すでにオープン後に再度呼び出された場合は何もしない。''' 89 | if not self.__isopen: 90 | self.__ezcom = win32com.client.Dispatch('EZNcAut.DispEZNcCommunication') 91 | errcd = self.__ezcom.SetTCPIPProtocol(self.__ip, int(self.__port)) 92 | self.__unitno = M700.alloc_unitno() 93 | self.__raise_error(errcd) 94 | # 引数: マシンタイプ番号(固定), ユニット番号, タイムアウト100ミリ秒, COMホスト名 95 | # マシンタイプ6=EZNC_SYS_MELDAS700M(マシニングセンタ系三菱CNC M700/M700V/M70/M70V) 96 | # ユニット番号は、1~255内で一意ものを指定する必要がある。 97 | errcd = self.__ezcom.Open2(6, self.__unitno, 30, 'EZNC_LOCALHOST') 98 | self.__raise_error(errcd) 99 | self.__isopen = True 100 | 101 | def close(self): 102 | '''コネクションを閉じる。 103 | 内部でエラーが起こっても例外は呼び出し元に返さない 104 | ''' 105 | try: 106 | M700.release_unitno(self.__unitno) #ユニット番号の開放 107 | self.__isopen = False 108 | self.__ezcom.Close() 109 | except: 110 | pass 111 | try: 112 | self.__ezcom.Release() 113 | except: 114 | pass 115 | 116 | def is_open(self): 117 | '''__open()処理後、接続が開いているか確認する。 118 | 119 | Return: 120 | bool: 接続が開いているならTrue 121 | ''' 122 | with self.__lock: 123 | try: 124 | self.__open() 125 | except: 126 | pass 127 | return self.__isopen 128 | 129 | # --- NC情報取得関連 --- 130 | 131 | def get_drive_infomation(self): 132 | '''利用可能なドライブ名を返す。 133 | 注意:ドライブ名は本来 "ドライブ名:CRLFドライブ名:CRLF...ドライブ名:CRLF¥0"で取得するので、 134 | 複数のドライブが存在する場合は、splitする必要がある。 135 | 136 | Return: 137 | str: ドライブ情報 138 | ''' 139 | with self.__lock: 140 | self.__open() 141 | errcd, drive_info = self.__ezcom.File_GetDriveInformation() 142 | self.__raise_error(errcd) 143 | return drive_info[0:4] 144 | 145 | def get_version(self): 146 | '''NCのバージョンを返す 147 | 148 | Return: 149 | str: バージョン情報 150 | ''' 151 | with self.__lock: 152 | self.__open() 153 | errcd, version = self.__ezcom.System_GetVersion(1, 0) 154 | self.__raise_error(errcd) 155 | return version 156 | 157 | def get_current_position(self, axisno): 158 | '''現在座標位置取得。 159 | 160 | Args: 161 | axisno (M700.Position.*): X or Y or Zを引数に渡す。 162 | 163 | Return: 164 | float: 現在座標位置 165 | ''' 166 | with self.__lock: 167 | if not isinstance(axisno, M700.Position): 168 | raise Exception('列挙体[M700.Position.*]を指定してください。') 169 | # in_1:取得したい軸。1=x, 2=y, 3=z 170 | # pos:現在位置。 171 | self.__open() 172 | errcd, pos = self.__ezcom.Position_GetCurrentPosition(axisno.value) 173 | self.__raise_error(errcd) 174 | return pos 175 | 176 | def get_run_status(self): 177 | '''運転状態取得。 178 | 179 | Return: 180 | M700.RunStatus: 列挙体[M700.RunStatus]を返す。 181 | ''' 182 | with self.__lock: 183 | # in_1:運転の種類。1=自動運転中であるか? 184 | # status:0=自動運転中でない。1=自動運転中である。 185 | self.__open() 186 | errcd, status = self.__ezcom.Status_GetRunStatus(1) 187 | self.__raise_error(errcd) 188 | if M700.RunStatus.AUTO_RUN.value == status: 189 | return M700.RunStatus.AUTO_RUN 190 | else: 191 | return M700.RunStatus.NOT_AUTO_RUN 192 | 193 | def get_rpm(self): 194 | '''回転数(0~[rpm])取得。 195 | 196 | Return: 197 | int: 回転数 198 | ''' 199 | with self.__lock: 200 | # in_1:指定した主軸のパラメータ番号を指定。2=主軸(SR、SF)回転速度。0~[rpm] 201 | # in_2:主軸番号を指定。 202 | # data:主軸の状態を返す。 203 | # info:主軸情報をUNICODE文字列として取得。 204 | self.__open() 205 | errcd, data, info = self.__ezcom.Monitor_GetSpindleMonitor(2, 1) 206 | self.__raise_error(errcd) 207 | return data 208 | 209 | def get_load(self): 210 | '''負荷(0~[%])取得。 211 | 212 | Return: 213 | int: 負荷 214 | ''' 215 | with self.__lock: 216 | # in_1:指定した主軸のパラメータ番号を指定。3=ロード。主軸モータの負荷。0~[%] 217 | # in_2:主軸番号を指定。 218 | # data:主軸の状態を返す。 219 | # info:主軸情報をUNICODE文字列として取得。 220 | self.__open() 221 | errcd, data, info = self.__ezcom.Monitor_GetSpindleMonitor(3, 1) 222 | self.__raise_error(errcd) 223 | return data 224 | 225 | def get_mgn_size(self): 226 | '''マガジンサイズ取得。 227 | 228 | Return: 229 | int: マガジンサイズ 230 | ''' 231 | with self.__lock: 232 | # size:マガジンポットの総組数。値:0~360(最大)。 233 | self.__open() 234 | errcd, size = self.__ezcom.ATC_GetMGNSize() 235 | self.__raise_error(errcd) 236 | return size 237 | 238 | def get_mgn_ready(self): 239 | '''装着済みの工具番号取得。 240 | 241 | Return: 242 | int: 工具番号 243 | ''' 244 | with self.__lock: 245 | # in_1:マガジン番号を指定。値:1~2(M700/M800シリーズでは、値を設定しても無効) 246 | # in_2:待機状態を指定。0=装着の工具番号、1=待機1の工具番号。2,3,4=1と同じ。 247 | # toolno:工具の番号を返す。値は、1~99999999(最大) 248 | self.__open() 249 | errcd, toolno = self.__ezcom.ATC_GetMGNReady2(1, 0) 250 | self.__raise_error(errcd) 251 | return toolno 252 | 253 | def get_toolset_size(self): 254 | '''ツールセットのサイズ取得 255 | ツールセットとは補正値NOのこと 256 | 257 | Return: 258 | int: ツールセットサイズ 259 | ''' 260 | with self.__lock: 261 | # plSize:200=200[組] 262 | self.__open() 263 | errcd, size = self.__ezcom.Tool_GetToolSetSize() 264 | self.__raise_error(errcd) 265 | return size 266 | 267 | def get_tool_offset_h(self, toolset_no): 268 | '''工具組番号の長オフセット値 269 | 270 | Return: 271 | int: 長 272 | ''' 273 | with self.__lock: 274 | # lType:工具オフセットのタイプ 4=マシニングセンタ系タイプⅡ 275 | # lKind:オフセット量の種類 0=長, 1=長摩耗, 2=径, 3=径摩耗 276 | # lToolSetNo:工具組番号 277 | # pdOffset As DOUBLE* (O)オフセット量 278 | # plNo As LONG* (O)仮想刃先点番号 279 | self.__open() 280 | errcd, h, plno = self.__ezcom.Tool_GetOffset2(4, 0, toolset_no) 281 | self.__raise_error(errcd) 282 | return h 283 | 284 | def get_tool_offset_d(self, toolset_no): 285 | '''工具組番号の長オフセット径 286 | 287 | Return: 288 | int: 径 289 | ''' 290 | with self.__lock: 291 | self.__open() 292 | errcd, d, plno = self.__ezcom.Tool_GetOffset2(4, 2, toolset_no) 293 | self.__raise_error(errcd) 294 | return d 295 | 296 | def set_tool_offset_h(self, toolset_no, h): 297 | '''工具組番号オフセット長補正値をセットする''' 298 | with self.__lock: 299 | # lType:工具オフセットのタイプ 4=マシニングセンタ系タイプⅡ 300 | # lKind:オフセット量の種類 0=長, 1=長摩耗, 2=径, 3=径摩耗 301 | # lToolSetNo:工具組番号 302 | # pdOffset As DOUBLE* オフセット量 303 | # plNo As LONG* 仮想刃先点番号 304 | self.__open() 305 | errcd = self.__ezcom.Tool_SetOffset(4, 0, toolset_no, h, 0) 306 | self.__raise_error(errcd) 307 | errcd = self.__ezcom.Tool_SetOffset(4, 2, toolset_no, d, 0) 308 | self.__raise_error(errcd) 309 | 310 | def set_tool_offset_d(self, toolset_no, d): 311 | '''工具組番号オフセット径補正値をセットする''' 312 | with self.__lock: 313 | self.__open() 314 | errcd = self.__ezcom.Tool_SetOffset(4, 2, toolset_no, d, 0) 315 | self.__raise_error(errcd) 316 | 317 | def get_program_number(self, progtype): 318 | '''サーチ完了、又は自動運転中のプログラムの番号を取得。 319 | 320 | Args: 321 | progtype (M700.ProgramType.*): MAIN or SUBを引数に渡す。 322 | 323 | Return: 324 | str: プログラム番号 325 | ''' 326 | with self.__lock: 327 | if not isinstance(progtype, M700.ProgramType): 328 | raise Exception('列挙体[M700.ProgramType.*]を指定してください。') 329 | 330 | # in_1:0=メインプログラム, 1=サブプログラム 331 | self.__open() 332 | errcd, msg = self.__ezcom.Program_GetProgramNumber2(progtype.value) 333 | self.__raise_error(errcd) 334 | return msg 335 | 336 | def get_alerm(self): 337 | '''アラートを取得。 338 | 339 | Return: 340 | str: エラーメッセージ 341 | ''' 342 | with self.__lock: 343 | # in_1:取得するメッセージ行数。1~10(最大) 344 | # in_2:取得するアラーム種類。 345 | # msg:エラーメッセージ 346 | self.__open() 347 | errcd, msg = self.__ezcom.System_GetAlarm2(3, 0) 348 | self.__raise_error(errcd) 349 | return msg 350 | 351 | # --- NCプログラムファイル操作関連 --- 352 | 353 | def read_file(self, path): 354 | '''ファイルを読み出しする。 355 | 356 | Args: 357 | path (str): 絶対パス exp) M01:¥PRG¥USER¥100 358 | Return: 359 | bytes: 読み出したバイトデータを返す。 360 | ''' 361 | with self.__lock: 362 | self.__open() 363 | try: 364 | errcd = self.__ezcom.File_OpenFile3(path, M700.NCProgramFileOpenMode.READ.value) 365 | self.__raise_error(errcd) 366 | result = b'' 367 | while True: 368 | errcd, data = self.__ezcom.File_ReadFile2(256) #一回で読み出すデータサイズをバイト数 369 | self.__raise_error(errcd) 370 | result += data #読み出したバイトデータの配列をVARIANT 371 | if len(data) < 256: 372 | break 373 | return result 374 | finally: 375 | try: 376 | self.__ezcom.File_CloseFile2() 377 | except: 378 | pass 379 | 380 | def write_file(self, path, data): 381 | '''ファイルに書き込みする。 382 | 383 | Args: 384 | path (str): 絶対パス exp) M01:¥PRG¥USER¥100 385 | data (bytes): 書き込むデータをバイトデータで渡す 386 | ''' 387 | with self.__lock: 388 | self.__open() 389 | try: 390 | errcd = self.__ezcom.File_OpenFile3(path, M700.NCProgramFileOpenMode.OVER_WRITE.value) 391 | self.__raise_error(errcd) 392 | errcd = self.__ezcom.File_WriteFile(memoryview(data)) #書き込むデータをバイトデータの配列 393 | self.__raise_error(errcd) 394 | finally: 395 | try: 396 | self.__ezcom.File_CloseFile2() 397 | except: 398 | pass 399 | 400 | def delete_file(self, path): 401 | '''パス名を指定してファイルを削除する。 402 | 403 | Args: 404 | path (str): 絶対パス exp) M01:¥PRG¥USER¥100 405 | ''' 406 | with self.__lock: 407 | self.__open() 408 | errcd = self.__ezcom.File_Delete2(path) 409 | self.__raise_error(errcd) 410 | 411 | # --- NCディレクトリ操作関連 -- 412 | 413 | def find_dir(self, path): 414 | '''パス名を指定してファイルを検索する。 415 | 416 | Args: 417 | path (str): ディレクトリパス exp) M01:¥PRG¥USER¥ 418 | Return: 419 | list: 検索結果のリスト。中身は辞書データで1件ごとのデータを管理。 420 | exp) [{ 'type': 'file', 'name': '100', 'size': '19', 'comment': 'BY IKEHARA' }, ...] 421 | ''' 422 | with self.__lock: 423 | result = [] 424 | 425 | try: 426 | self.__open() 427 | 428 | #M01 → Mユニット番号16進数 429 | path = path.replace("M01", "M{:02X}".format(self.__unitno)) 430 | 431 | # 指定パス内のディレクトリ情報を取得 (-1で'ディレクトリ名\tサイズ'の文字列を取得) 432 | errcd, info = self.__ezcom.File_FindDir2(path, -1) 433 | self.__raise_error(errcd) 434 | while True: 435 | # ディレクトリ情報有り 436 | if errcd > 1: 437 | dir_info = info.split('\t') 438 | data = { 439 | 'type': 'folder', 440 | 'name': dir_info[0], 441 | 'size': '{:,}'.format(int(dir_info[1])), 442 | 'comment': None 443 | } 444 | result.append(data) 445 | else: 446 | break 447 | errcd, info = self.__ezcom.File_FindNextDir2() 448 | self.__raise_error(errcd) 449 | 450 | # 一旦リセット 451 | errcd = self.__ezcom.File_ResetDir() 452 | self.__raise_error(errcd) 453 | 454 | # 指定パス内のファイル情報を取得 (5で'ファイル名\tサイズ\tコメント'の文字列を取得) 455 | errcd, info = self.__ezcom.File_FindDir2(path, 5) 456 | self.__raise_error(errcd) 457 | while True: 458 | # ファイル情報有り 459 | if errcd > 1: 460 | dir_info = info.split('\t') 461 | data = { 462 | 'type': 'file', 463 | 'name': dir_info[0], 464 | 'size': '{:,}'.format(int(dir_info[1])), 465 | 'comment': dir_info[2] 466 | } 467 | result.append(data) 468 | else: 469 | break 470 | errcd, info = self.__ezcom.File_FindNextDir2() 471 | self.__raise_error(errcd) 472 | finally: 473 | try: 474 | errcd = self.__ezcom.File_ResetDir() 475 | self.__raise_error(errcd) 476 | except: 477 | pass 478 | 479 | return result 480 | 481 | # --- NCデバイス操作関連 --- 482 | 483 | def __setting_dev(self, dev, data=0): 484 | '''デバイスの設定を行う。 485 | 486 | Args: 487 | dev (str): デバイス指定。exp) M810, D10 488 | data (int): 値。ビットを立てる場合は1、下げる場合は0。 489 | read_devの場合は、ダミーとして適当な文字を入れる。 490 | ''' 491 | data_type = 0 # 1 or 4 or 8 exp) M=1(ビット型 1bit), D=4(ワード型 16bit) 492 | if dev[0] == 'M': 493 | data_type = 1 494 | elif dev[0] == 'D': 495 | data_type = 4 496 | else: 497 | Exception('Mデバイス、又はDデバイスを設定して下さい。') 498 | 499 | # in_1:デバイス文字列(設定するデバイス文字列の配列をVARIANTとして指定) 500 | # in_2:データ種別 501 | # in_3:デバイス値配列 502 | vDevice = VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_BSTR, [dev]) 503 | vDataType = VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I4, [data_type]) 504 | vValue = VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_I4, [data]) # 書き込むデータは現在数値のみ 505 | errcd = self.__ezcom.Device_SetDevice(vDevice, vDataType, vValue) 506 | self.__raise_error(errcd) 507 | 508 | def __delall_dev(self): 509 | '''デバイス設定を全て削除。''' 510 | errcd = self.__ezcom.Device_DeleteAll() 511 | self.__raise_error(errcd) 512 | 513 | def read_dev(self, dev): 514 | '''デバイス読み出し。__setting_devで設定したデバイスの値を読み込む。 515 | 516 | Args: 517 | dev (str): デバイス番号 exp) M900 518 | Return: 519 | int: 読み出したデータの値を返す。 520 | ''' 521 | with self.__lock: 522 | self.__open() 523 | self.__setting_dev(dev) 524 | errcd, value = self.__ezcom.Device_Read() # value:デバイス値配列が返ってくる。 525 | self.__raise_error(errcd) 526 | self.__delall_dev() 527 | return value[0] 528 | 529 | def write_dev(self, dev, data): 530 | '''デバイス書き込み。__setting_devで設定したデバイスに値を書き込む。 531 | 532 | Args: 533 | dev (str): デバイス番号 exp) M900 534 | data (int): 書き込む値 535 | ''' 536 | with self.__lock: 537 | self.__open() 538 | self.__setting_dev(dev, data) 539 | errcd = self.__ezcom.Device_Write() 540 | self.__delall_dev() 541 | self.__raise_error(errcd) 542 | 543 | # --- エラー出力関連 --- 544 | 545 | def __raise_error(self, errcd): 546 | '''エラーコードから、エラーの内容をExceptionとして返す。 547 | 548 | エラーがない場合(エラーコードが0)は何もしない。 549 | エラーの内容は、辞書で {'16進数エラーコード': 'error detail message'} の形で登録。 550 | 551 | Raises: 552 | Exception: エラーメッセージ 553 | ''' 554 | __errmap = { 555 | "0x80a00101" : "通信回線がオープンされていません", 556 | "0x80a00104" : "2重オープンエラー", 557 | "0x80a00105" : "引数のデータタイプが不正", 558 | "0x80a00106" : "引数のデータ範囲が不正", 559 | "0x80a00107" : "サポートしていない", 560 | "0x80a00109" : "通信回線がオープンできません", 561 | "0x80a0010a" : "引数がnullポインタです。", 562 | "0x80a0010b" : "引数のデータ不正", 563 | "0x80a0010c" : "COMMポートハンドルエラー", 564 | "0x80b00101" : "メモリの確保ができない", 565 | "0x80b00102" : "EZSocketPcのエラーが取得できない", 566 | "0x80b00201" : "モード指定不正", 567 | "0x80b00202" : "未ファイルオープン", 568 | "0x80b00203" : "ファイルが既に存在する", 569 | "0x80b00204" : "既にファイルオープンしている", 570 | "0x80b00205" : "テンポラリファイルを作成できない", 571 | "0x80b00206" : "書き込みモード指定でファイルオープンしていない", 572 | "0x80b00207" : "書き込みデータサイズ不正", 573 | "0x80b00208" : "書き込みできない状態", 574 | "0x80b00209" : "読み出しモード指定でファイルオープンしていない", 575 | "0x80b0020a" : "読み出しできない状態", 576 | "0x80b0020b" : "テンポラリファイルを作成できない", 577 | "0x80b0020c" : "ファイルが存在しない(readモード)", 578 | "0x80b0020d" : "ファイルがオープンできない", 579 | "0x80b0020e" : "ファイルのパスが不正", 580 | "0x80b0020f" : "読み出しファイルが不正", 581 | "0x80b00210" : "書き込みファイルが不正", 582 | "0x80b00301" : "オートメーション呼び出しでローカル接続時のホスト名が不正", 583 | "0x80b00302" : "TCP/IP通信が設定されていない", 584 | "0x80b00303" : "既に通信中なので設定できない", 585 | "0x80b00304" : "下位モジュールがない", 586 | "0x80b00305" : "EZSocketPcオブジェクトが生成できない", 587 | "0x80b00401" : "データが存在しない", 588 | "0x80b00402" : "データ重複", 589 | "0x80b00501" : "パラメータ情報ファイルがない", 590 | "0x80020190" : "NCカード番号不正", 591 | "0x80020102" : "デバイスがオープンされていない", 592 | "0x80020132" : "コマンド不正", 593 | "0x80020133" : "通信パラメータデータ範囲不正", 594 | "0x80030143" : "ファイルシステムに異常がある", 595 | "0x80030191" : "ディレクトリが存在しない", 596 | "0x8003019b" : "ドライブが存在しない", 597 | "0x800301a2" : "ディレクトリが存在しない", 598 | "0x800301a8" : "ドライブが存在しない", 599 | "0x80050d90" : "系統、軸指定が不正", 600 | "0x80050d02" : "アラーム種類が不正", 601 | "0x80050d03" : "NCとPC間の通信データにエラーがある", 602 | "0x80041194" : "寿命管理データの種類指定不正", 603 | "0x80041195" : "設定データ範囲オーバ", 604 | "0x80041196" : "設定工具番号不一致", 605 | "0x80041197" : "指定工具番号が仕様外", 606 | "0x80040190" : "系統、軸指定が不正", 607 | "0x80040191" : "大区分番号不正", 608 | "0x80040192" : "小区分番号不正", 609 | "0x80040196" : "アプリケーションが用意したバッファに入りきらない", 610 | "0x80040197" : "データタイプ不正", 611 | "0x8004019d" : "データが読み出せない状態にある", 612 | "0x8004019f" : "書き込み専用データ", 613 | "0x800401a0" : "軸指定不正", 614 | "0x800401a1" : "データ番号不正", 615 | "0x800401a3" : "読み出しデータなし", 616 | "0x8004019a" : "読み出しデータ範囲不正", 617 | "0x80040290" : "系統、軸指定が不正", 618 | "0x80040291" : "大区分番号不正", 619 | "0x80040292" : "小区分番号不正", 620 | "0x80040296" : "アプリケーションが用意したバッファに入りきらない", 621 | "0x80040297" : "データタイプ不正", 622 | "0x8004029b" : "読み出し専用データ", 623 | "0x8004029e" : "データが書き込めない状態にある", 624 | "0x800402a0" : "軸指定不正", 625 | "0x8004024d" : "安全パスワードロック中", 626 | "0x800402a2" : "SRAM開放パラメータ不正によりフォーマット中止した", 627 | "0x800402a4" : "編集ァイルを登録できない(既に編集中)", 628 | "0x800402a5" : "編集ファイルを解除できない", 629 | "0x800402a3" : "書き込み先データなし", 630 | "0x8004029a" : "書き込みデータ範囲不正", 631 | "0x800402a6" : "安全パスワード未設定", 632 | "0x800402a7" : "安全データ整合性チェックエラー", 633 | "0x800402a9" : "安全用データタイプ不", 634 | "0x800402a8" : "工具データソート中で書き込みできない", 635 | "0x80040501" : "高速読み出し登録されていない", 636 | "0x80040402" : "プライオリティ指定不正", 637 | "0x80040401" : "登録数をオーバした", 638 | "0x80040490" : "アドレス不正", 639 | "0x80040491" : "大区分番号不正", 640 | "0x80040492" : "小区分番号不正", 641 | "0x80040497" : "データタイプ不正", 642 | "0x8004049b" : "読み出し専用データ", 643 | "0x8004049d" : "データが読み出せない状態にある", 644 | "0x8004049f" : "書き込み専用データ", 645 | "0x800404a0" : "軸指定不正", 646 | "0x80040ba3" : "再ねじ切り位置設定なし", 647 | "0x80030101" : "既に別ディレクトリがオープンされている", 648 | "0x80030103" : "データサイズオーバ", 649 | "0x80030148" : "ファイル名が長い", 650 | "0x80030198" : "ファイル名フォーマットが不正", 651 | "0x80030190" : "オープンされていない", 652 | "0x80030194" : "ファイル情報リードエラー", 653 | "0x80030102" : "すでに別ディレクトリがオープンされている(PCのみ)", 654 | "0x800301a0" : "オープンされていない", 655 | "0x800301a1" : "ファイルが存在しない", 656 | "0x800301a5" : "ファイル情報リードエラー", 657 | "0x80030447" : "コピーできない状態にある(運転中)", 658 | "0x80030403" : "登録本数オーバ", 659 | "0x80030401" : "コピー先ファイルが既に存在する", 660 | "0x80030443" : "ファイルシステムに異常がある", 661 | "0x80030448" : "ファイル名が長い", 662 | "0x80030498" : "ファイル名フォーマットが不正", 663 | "0x80030404" : "メモリ容量オーバ", 664 | "0x80030491" : "ディレクトリが存在しない", 665 | "0x8003049b" : "ドライブが存在しない", 666 | "0x80030442" : "ファイルが存在しない", 667 | "0x80030446" : "コピーできない状態にある(PLC動作中)", 668 | "0x80030494" : "転送元ファイルが読めない", 669 | "0x80030495" : "転送先ファイルに書き込めない", 670 | "0x8003044a" : "コピーできない状態にある(プロテクト中)", 671 | "0x80030405" : "照合エラー", 672 | "0x80030449" : "照合機能をサポートしていない", 673 | "0x8003044c" : "ファイルコピー中", 674 | "0x80030490" : "ファイルがオープンされていない", 675 | "0x8003044d" : "安全パスワードロック中", 676 | "0x8003049d" : "ファイルフォーマット不正", 677 | "0x8003049e" : "パスワードが異なる", 678 | "0x800304a4" : "ファイルが生成できない(PCのみ)", 679 | "0x800304a3" : "ファイルをオープンできない(PCのみ)", 680 | "0x80030402" : "コピー先ファイルが既に存在する", 681 | "0x800304a7" : "ファイル名フォーマットが不正", 682 | "0x800304a2" : "ディレクトリが存在しない", 683 | "0x800304a8" : "ドライブが存在しない", 684 | "0x800304a1" : "ファイルが存在しない", 685 | "0x800304a5" : "転送元ファイルが読めない", 686 | "0x800304a6" : "転送先ファイルに書き込めない", 687 | "0x80030406" : "ディスク容量オーバ", 688 | "0x800304a0" : "ファイルがオープンされていない", 689 | "0x80030201" : "削除できないファイル", 690 | "0x80030242" : "ファイルが存在しない", 691 | "0x80030243" : "ファイルシステムに異常がある", 692 | "0x80030247" : "削除できない状態にある(運転中)", 693 | "0x80030248" : "ファイル名が長い", 694 | "0x8003024a" : "ファイルが削除できない状態にある(プロテクト中)", 695 | "0x80030291" : "ディレクトリが存在しない", 696 | "0x80030298" : "ファイル名フォーマットが不正", 697 | "0x8003029b" : "ドライブが存在しない", 698 | "0x80030202" : "削除できないファイル", 699 | "0x800302a7" : "ファイル名フォーマットが不正", 700 | "0x800302a2" : "ディレクトリが存在しない", 701 | "0x800302a8" : "ドライブが存在しない", 702 | "0x800302a1" : "ファイルが存在しない", 703 | "0x80030301" : "新ファイル名が既に存在する", 704 | "0x80030342" : "ファイルが存在しない", 705 | "0x80030343" : "ファイルシステムに異常がある", 706 | "0x80030347" : "リネームできない状態にある(運転中)", 707 | "0x80030348" : "ファイル名が長い", 708 | "0x8003034a" : "リネームできない状態にある(プロテクト中)", 709 | "0x80030391" : "ディレクトリが存在しない", 710 | "0x80030398" : "ファイル名フォーマットが不正", 711 | "0x8003039b" : "ドライブが存在しない", 712 | "0x80030303" : "リネームできない", 713 | "0x80030305" : "新旧ファイル名が同じ", 714 | "0x80030302" : "新ファイル名が既に存在する", 715 | "0x800303a7" : "ファイル名フォーマットが不正", 716 | "0x800303a2" : "ディレクトリが存在しない", 717 | "0x800303a8" : "ドライブが存在しない", 718 | "0x800303a1" : "ファイルが存在しない", 719 | "0x80030691" : "ディレクトリが存在しない", 720 | "0x8003069b" : "ドライブが存在しない", 721 | "0x80030643" : "ファイルシステムに異常がある", 722 | "0x80030648" : "ファイル名が長いまたはフォーマットが不正", 723 | "0x800306a2" : "ディレクトリが存在しない(PCのみ)", 724 | "0x800306a8" : "ドライブが存在しない(PCのみ)", 725 | "0x80030701" : "アプリケーションが用意したバッファに入りきらない", 726 | "0x80030794" : "ドライブ情報リードエラー", 727 | "0x82020001" : "すでにオープンされている", 728 | "0x82020002" : "オープンされていない", 729 | "0x82020004" : "カードが存在しない", 730 | "0x82020006" : "チャンネル番号不正", 731 | "0x82020007" : "ファイルディスクプリタ不正", 732 | "0x8202000a" : "コネクトされていない", 733 | "0x8202000b" : "クローズされていない", 734 | "0x82020014" : "タイムアウト", 735 | "0x82020015" : "データ不正", 736 | "0x82020016" : "キャンセル要求により終了した", 737 | "0x82020017" : "パケットサイズ不正", 738 | "0x82020018" : "タスク終了により終了した", 739 | "0x82020032" : "コマンド不正", 740 | "0x82020033" : "設定データ不正", 741 | "0x80060001" : "データリードキャッシュが無効", 742 | "0x80060090" : "アドレス不正", 743 | "0x80060091" : "大区分番号不正", 744 | "0x80060092" : "小区分番号不正", 745 | "0x80060097" : "データタイプ不正", 746 | "0x8006009a" : "データ範囲不正", 747 | "0x8006009d" : "データが読み出せない状態にある", 748 | "0x8006009f" : "データタイプ不正", 749 | "0x800600a0" : "軸指定不正", 750 | "0x80070140" : "作業領域を確保できない", 751 | "0x80070142" : "ファイルをオープンできない", 752 | "0x80070147" : "ファイルがオープンできない状態にある(運転中)", 753 | "0x80070148" : "ファイルパスが長い", 754 | "0x80070149" : "未サポート(CF未対応)", 755 | "0x80070192" : "すでにオープンされている", 756 | "0x80070199" : "最大ファイルオープン数を越えた", 757 | "0x8007019f" : "工具データソート中でオープンができない", 758 | "0x800701b0" : "安全パスワードが未認証", 759 | "0x80070290" : "ファイルがオープンされていない", 760 | "0x80070340" : "作業領域を確保できない", 761 | "0x80070347" : "ファイルが生成できない状態にある(運転中)", 762 | "0x80070348" : "ファイルパスが長い", 763 | "0x80070349" : "未サポート(CF未対応)", 764 | "0x80070392" : "すでに生成されている", 765 | "0x80070393" : "ファイルを生成できない", 766 | "0x80070399" : "最大ファイルオープン数を越えた", 767 | "0x8007039b" : "ドライブが存在しない", 768 | "0x80070490" : "ファイルがオープンされていない", 769 | "0x80070494" : "ファイル情報リードエラー", 770 | "0x80070549" : "書き込み不可", 771 | "0x80070590" : "ファイルがオープンされていない", 772 | "0x80070595" : "ファイル書き込みエラー", 773 | "0x80070740" : "ファイル削除エラー", 774 | "0x80070742" : "ファイルが存在しない3-6", 775 | "0x80070747" : "ファイルが削除できない状態にある(運転中)", 776 | "0x80070748" : "ファイルパスが長い", 777 | "0x80070749" : "未サポート(CF未対応)", 778 | "0x80070792" : "ファイルがオープンされている", 779 | "0x8007079b" : "ドライブが存在しない", 780 | "0x80070842" : "ファイルが存在しない", 781 | "0x80070843" : "リネームできないファイル", 782 | "0x80070848" : "ファイルパスが長い", 783 | "0x80070849" : "未サポート(CF未対応)", 784 | "0x80070892" : "ファイルがオープンされている", 785 | "0x80070899" : "最大ファイルオープン数を越えた", 786 | "0x8007089b" : "ドライブが存在しない", 787 | "0x80070944" : "コマンド不正(未対応)", 788 | "0x80070990" : "オープンされていない", 789 | "0x80070994" : "リードエラー", 790 | "0x80070995" : "ライトエラー", 791 | "0x80070996" : "アプリケーションが用意したバッファに入りきらない", 792 | "0x80070997" : "データタイプ不正", 793 | "0x80070949" : "未サポート(CF未対応)", 794 | "0x80070a40" : "作業領域を確保できない", 795 | "0x80070a47" : "ディレクトリがオープンできない状態にある(運転中)", 796 | "0x80070a48" : "ファイルパスが長い", 797 | "0x80070a49" : "未サポート(CF未対応)", 798 | "0x80070a91" : "ディレクトリが存在しない", 799 | "0x80070a92" : "すでにオープンされている", 800 | "0x80070a99" : "最大ディレクトリオープン数を越えた", 801 | "0x80070a9b" : "ドライブが存在しない", 802 | "0x80070b90" : "ディレクトリがオープンされていない", 803 | "0x80070b91" : "ディレクトリが存在しない", 804 | "0x80070b96" : "アプリケーションが用意したバッファに入りきらない", 805 | "0x80070d90" : "ディレクトリがオープンされていない", 806 | "0x80070e48" : "ファイルパスが長い", 807 | "0x80070e49" : "サポート(CF未対応)", 808 | "0x80070e94" : "ファイル情報読み込みエラー", 809 | "0x80070e99" : "最大ファイルオープン数を越えた", 810 | "0x80070e9b" : "ドライブが存在しない", 811 | "0x80070f48" : "ファイルパスが長い", 812 | "0x80070f49" : "未サポート(CF未対応)", 813 | "0x80070f94" : "ファイル情報読み込みエラー", 814 | "0x80070f90" : "ファイルがオープンされていないた", 815 | "0x80070f9b" : "ドライブが存在しない", 816 | "0x8007099c" : "SRAM開放パラ不正でフォーマット中止", 817 | "0xf00000ff" : "引数が不正", 818 | "0xffffffff" : "データが読み出せない/書き込めない状態" 819 | } 820 | 821 | # 0: エラーなし, 1以上: File_FindDir2時にファイル情報ありの時 822 | if errcd == 0 or errcd >= 1: 823 | return 824 | 825 | hex_str = '0x' + format(errcd & 0xffffffff, 'x') 826 | msg = __errmap.get(hex_str, 'Unkown error') # 辞書に無ければUnkown error 827 | 828 | # '通信回線がオープンされてない'or'コネクトされていない'ならclose扱い 829 | if '0x80a00101' == hex_str or '0x8202000a' == hex_str: 830 | self.close() 831 | raise Exception('Error=(IP:' + self.__ip + ') ' + hex_str + ': ' + msg) 832 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pywin32 2 | -------------------------------------------------------------------------------- /test_m700.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | ''' 3 | 本テストは三菱M700のテストスクリプトです。 4 | 5 | ※注意 デバイスの操作によって、物理的な機械が動く可能性があります。 6 | 必ず安全を確かめ、テストコード内の操作を理解した上で実行して下さい。 7 | ''' 8 | import os 9 | import sys 10 | import unittest 11 | 12 | from m700 import M700 13 | 14 | 15 | class TestM700(unittest.TestCase): 16 | 17 | @classmethod 18 | def setUpClass(cls): 19 | '''テストクラスが初期化される際に一度だけ呼ばれる。''' 20 | print('----- TestM700 start ------') 21 | cls.m700 = M700.get_connection('192.168.48.173:683') 22 | 23 | @classmethod 24 | def tearDownClass(cls): 25 | '''テストクラスが解放される際に一度だけ呼ばれる。''' 26 | cls.m700.close() 27 | print('----- TestM700 end ------') 28 | 29 | def setUp(self): 30 | '''テストごとに開始前に必ず実行''' 31 | if not self.m700.is_open(): 32 | self.skipTest('指定されたIPに接続できません。電源が入っていない可能性があります。') 33 | 34 | def test_result_type(self): 35 | '''内部情報を取得し、各メソッドが返す型が正常かテスト。 36 | 37 | 値はその時々で変わる為、正常に実行できるかどうかのみのチェックで良しとする。 38 | ''' 39 | self.assertIs(type(self.m700.get_drive_infomation()), str) 40 | self.assertIs(type(self.m700.get_version()), str) 41 | self.assertIs(type(self.m700.get_current_position(M700.Position.X)), float) 42 | self.assertIs(type(self.m700.get_run_status()), M700.RunStatus) 43 | self.assertIs(type(self.m700.get_rpm()), int) 44 | self.assertIs(type(self.m700.get_load()), int) 45 | self.assertIs(type(self.m700.get_mgn_size()), int) 46 | self.assertIs(type(self.m700.get_mgn_ready()), int) 47 | self.assertIs(type(self.m700.get_toolset_size()), int) 48 | self.assertIs(type(self.m700.get_program_number(M700.ProgramType.MAIN)), str) 49 | self.assertIs(type(self.m700.get_alerm()), str) 50 | 51 | def test_operate_program_file(self): 52 | '''加工プログラム読み書きテスト。''' 53 | drivenm = self.m700.get_drive_infomation() 54 | self.m700.write_file(drivenm + '¥PRG¥USER¥__TEST__.txt', b'TEST_WRITE') 55 | self.assertEqual(self.m700.read_file(drivenm + '¥PRG¥USER¥__TEST__.txt'), b'TEST_WRITE') 56 | self.m700.delete_file(drivenm + '¥PRG¥USER¥__TEST__.txt') 57 | 58 | def test_dev_operation(self): 59 | '''M,Dデバイスの読み書きテスト。''' 60 | self.m700.write_dev('M900', 1) 61 | self.assertEqual(self.m700.read_dev('M900'), 1) 62 | self.m700.write_dev('M900', 0) 63 | self.assertEqual(self.m700.read_dev('M900'), 0) 64 | self.m700.write_dev('D200', 10) 65 | self.assertEqual(self.m700.read_dev('D200'), 10) 66 | self.m700.write_dev('D200', 0) 67 | self.assertEqual(self.m700.read_dev('D200'), 0) 68 | 69 | if __name__ == '__main__': 70 | unittest.main() 71 | --------------------------------------------------------------------------------