├── .gitattributes ├── .gitignore ├── McProtocol.sln └── McProtocol ├── MCProtocol.cs └── McProtocol.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /McProtocol.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McProtocol", "McProtocol\McProtocol.csproj", "{A9A60439-B6AC-490E-97AC-BA2755A3222C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {A9A60439-B6AC-490E-97AC-BA2755A3222C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {A9A60439-B6AC-490E-97AC-BA2755A3222C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {A9A60439-B6AC-490E-97AC-BA2755A3222C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {A9A60439-B6AC-490E-97AC-BA2755A3222C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {ED4D7A45-2FC6-44E1-8CB9-EE7DDEDA1DB4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /McProtocol/MCProtocol.cs: -------------------------------------------------------------------------------- 1 | #define old //Now that .NET Standard is supported in UWP old code is Good 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using System.Threading; 7 | using System.Text; 8 | using System.Net.Sockets; 9 | using System.IO; 10 | #if !old 11 | using Windows.Networking; 12 | using Windows.Networking.Sockets; 13 | using Windows.Foundation; 14 | #endif 15 | using System.Runtime.InteropServices; 16 | 17 | 18 | namespace MCProtocol 19 | { 20 | public class PLCData 21 | { 22 | public static Mitsubishi.Plc PLC; 23 | 24 | } 25 | public class PLCData : PLCData 26 | { 27 | Mitsubishi.PlcDeviceType DeviceType; 28 | int Address; 29 | int Length; 30 | int LENGTH;//Length in bytes 31 | byte[] bytes; 32 | public PLCData(Mitsubishi.PlcDeviceType DeviceType, int Address, int Length) 33 | { 34 | this.DeviceType = DeviceType; 35 | this.Address = Address; 36 | 37 | string t = typeof(T).Name; 38 | switch (t) 39 | { 40 | case "Boolean": 41 | this.LENGTH = (Length / 16 + (Length % 16 > 0 ? 1 : 0)) * 2; 42 | this.Length = Length; 43 | break; 44 | case "Int32": 45 | this.LENGTH = 4 * Length; 46 | this.Length = Length * 2; 47 | break; 48 | case "Int16": 49 | this.LENGTH = 2 * Length; 50 | this.Length = Length; 51 | break; 52 | case "UInt16": 53 | this.LENGTH = 2 * Length; 54 | this.Length = Length; 55 | break; 56 | case "UInt32": 57 | this.LENGTH = 4 * Length; 58 | this.Length = Length * 2; 59 | break; 60 | case "Single": 61 | this.LENGTH = 4 * Length; 62 | this.Length = Length * 2; 63 | break; 64 | case "Double": 65 | this.LENGTH = 8 * Length; 66 | this.Length = Length * 4; 67 | break; 68 | case "Char": 69 | this.LENGTH = Length; 70 | this.Length = Length; 71 | break; 72 | default: 73 | throw new Exception("Type not supported by PLC."); 74 | } 75 | this.bytes = new byte[this.LENGTH]; 76 | 77 | } 78 | public T this[int i] 79 | { 80 | get 81 | { 82 | Union u = new Union(); 83 | string t = typeof(T).Name; 84 | switch (t) 85 | { 86 | case "Boolean": 87 | return (T)Convert.ChangeType(((this.bytes[i / 8] >> (i % 8)) % 2 == 1), typeof(T)); 88 | case "Int32": 89 | u.a = this.bytes[i * 4]; 90 | u.b = this.bytes[i * 4 + 1]; 91 | u.c = this.bytes[i * 4 + 2]; 92 | u.d = this.bytes[i * 4 + 3]; 93 | return (T)Convert.ChangeType(u.DINT, typeof(T)); 94 | case "Int16": 95 | u.a = this.bytes[i * 2]; 96 | u.b = this.bytes[i * 2 + 1]; 97 | return (T)Convert.ChangeType(u.INT, typeof(T)); 98 | case "UInt16": 99 | u.a = this.bytes[i * 2]; 100 | u.b = this.bytes[i * 2 + 1]; 101 | return (T)Convert.ChangeType(u.UINT, typeof(T)); 102 | case "UInt32": 103 | u.a = this.bytes[i * 4]; 104 | u.b = this.bytes[i * 4 + 1]; 105 | u.c = this.bytes[i * 4 + 2]; 106 | u.d = this.bytes[i * 4 + 3]; 107 | return (T)Convert.ChangeType(u.UDINT, typeof(T)); 108 | case "Single": 109 | u.a = this.bytes[i * 4]; 110 | u.b = this.bytes[i * 4 + 1]; 111 | u.c = this.bytes[i * 4 + 2]; 112 | u.d = this.bytes[i * 4 + 3]; 113 | return (T)Convert.ChangeType(u.REAL, typeof(T)); 114 | case "Char": 115 | return (T)Convert.ChangeType(this.ToString()[i], typeof(T)); 116 | default: 117 | throw new Exception("Type not recognized."); 118 | } 119 | } 120 | set 121 | { 122 | Union u = new Union(); 123 | string t = typeof(T).Name; 124 | switch (t) 125 | { 126 | case "Boolean": 127 | bool arg = Convert.ToBoolean(value); 128 | if (arg && (this.bytes[i / 8] >> (i % 8)) % 2 == 0) 129 | this.bytes[i / 8] += (byte)(1 << (i % 8)); 130 | else if (!arg && (this.bytes[i / 8] >> (i % 8)) % 2 == 1) 131 | this.bytes[i / 8] -= (byte)(1 << (i % 8)); 132 | return; 133 | case "Int32": 134 | u.DINT = Convert.ToInt32(value); 135 | this.bytes[i * 4] = u.a; 136 | this.bytes[i * 4 + 1] = u.b; 137 | this.bytes[i * 4 + 2] = u.c; 138 | this.bytes[i * 4 + 3] = u.d; 139 | return; 140 | case "Int16": 141 | u.INT = Convert.ToInt16(value); 142 | this.bytes[i * 2] = u.a; 143 | this.bytes[i * 2 + 1] = u.b; 144 | return; 145 | case "UInt32": 146 | u.UDINT = Convert.ToUInt32(value); 147 | this.bytes[i * 4] = u.a; 148 | this.bytes[i * 4 + 1] = u.b; 149 | this.bytes[i * 4 + 2] = u.c; 150 | this.bytes[i * 4 + 3] = u.d; 151 | return; 152 | case "UInt16": 153 | u.UINT = Convert.ToUInt16(value); 154 | this.bytes[i * 2] = u.a; 155 | this.bytes[i * 2] = u.b; 156 | return; 157 | case "Single": 158 | u.REAL = Convert.ToSingle(value); 159 | this.bytes[i * 4] = u.a; 160 | this.bytes[i * 4 + 1] = u.b; 161 | this.bytes[i * 4 + 2] = u.c; 162 | this.bytes[i * 4 + 3] = u.d; 163 | return; 164 | default: 165 | throw new Exception("Type not recognized."); 166 | } 167 | } 168 | } 169 | 170 | public async Task WriteData() 171 | { 172 | await PLC.WriteDeviceBlock(this.DeviceType, this.Address, Length, bytes); 173 | } 174 | public async Task ReadData() 175 | { 176 | this.bytes = await PLC.ReadDeviceBlock(DeviceType, this.Address, this.Length); 177 | } 178 | 179 | } 180 | [StructLayout(LayoutKind.Explicit)] 181 | public class Union 182 | { 183 | [FieldOffset(0)] 184 | public float REAL; 185 | [FieldOffset(0)] 186 | public short INT; 187 | [FieldOffset(0)] 188 | public uint UINT; 189 | [FieldOffset(0)] 190 | public int DINT; 191 | [FieldOffset(0)] 192 | public uint UDINT; 193 | [FieldOffset(0)] 194 | public char letter; 195 | [FieldOffset(0)] 196 | public byte bite; 197 | [FieldOffset(0)] 198 | public byte a; 199 | [FieldOffset(1)] 200 | public byte b; 201 | [FieldOffset(2)] 202 | public byte c; 203 | [FieldOffset(3)] 204 | public byte d; 205 | } 206 | 207 | public class Mitsubishi 208 | { 209 | //const int frameSize = 14;//11, 15, 20 210 | // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 211 | public enum McFrame 212 | { 213 | MC1E = 4, 214 | MC3E = 11, 215 | MC4E = 15 216 | 217 | } 218 | 219 | // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 220 | // PLCデバイスの種類を定義した列挙体 221 | public enum PlcDeviceType 222 | { 223 | // PLC用デバイス 224 | M = 0x90 225 | , SM = 0x91 226 | , L = 0x92 227 | , F = 0x93 228 | , V = 0x94 229 | , S = 0x98 230 | , X = 0x9C 231 | , Y = 0x9D 232 | , B = 0xA0 233 | , SB = 0xA1 234 | , DX = 0xA2 235 | , DY = 0xA3 236 | , D = 0xA8 237 | , SD = 0xA9 238 | , R = 0xAF 239 | , ZR = 0xB0 240 | , W = 0xB4 241 | , SW = 0xB5 242 | , TC = 0xC0 243 | , TS = 0xC1 244 | , TN = 0xC2 245 | , CC = 0xC3 246 | , CS = 0xC4 247 | , CN = 0xC5 248 | , SC = 0xC6 249 | , SS = 0xC7 250 | , SN = 0xC8 251 | , Z = 0xCC 252 | , TT 253 | , TM 254 | , CT 255 | , CM 256 | , A 257 | , Max 258 | } 259 | 260 | // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 261 | // PLCと接続するための共通のインターフェースを定義する 262 | public interface Plc : IDisposable 263 | { 264 | bool Connected { get; } 265 | Task Open(); 266 | int Close(); 267 | Task SetBitDevice(string iDeviceName, int iSize, int[] iData); 268 | Task SetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] iData); 269 | Task GetBitDevice(string iDeviceName, int iSize, int[] oData); 270 | Task GetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] oData); 271 | Task WriteDeviceBlock(string iDeviceName, int iSize, int[] iData); 272 | Task WriteDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, int[] iData); 273 | Task WriteDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, byte[] bData); 274 | Task ReadDeviceBlock(string iDeviceName, int iSize, int[] oData); 275 | Task ReadDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, int[] oData); 276 | Task ReadDeviceBlock(PlcDeviceType iType, int iAddress, int iSize); 277 | Task SetDevice(string iDeviceName, int iData); 278 | Task SetDevice(PlcDeviceType iType, int iAddress, int iData); 279 | Task GetDevice(string iDeviceName); 280 | Task GetDevice(PlcDeviceType iType, int iAddress); 281 | } 282 | // ######################################################################################## 283 | abstract public class McProtocolApp : Plc 284 | { 285 | public abstract bool Connected{ get; } 286 | // ==================================================================================== 287 | public McFrame CommandFrame { get; set; } // 使用フレーム 288 | public string HostName { get; set; } // ホスト名またはIPアドレス 289 | public int PortNumber { get; set; } // ポート番号 290 | public int Device { private set; get; } 291 | // ==================================================================================== 292 | // コンストラクタ 293 | protected McProtocolApp(string iHostName, int iPortNumber, McFrame frame) 294 | { 295 | CommandFrame = frame; 296 | //C70 = MC3E 297 | 298 | HostName = iHostName; 299 | PortNumber = iPortNumber; 300 | } 301 | 302 | // ==================================================================================== 303 | // 後処理 304 | public void Dispose() 305 | { 306 | Close(); 307 | } 308 | 309 | // ==================================================================================== 310 | public async Task Open() 311 | { 312 | await DoConnect(); 313 | Command = new McCommand(CommandFrame); 314 | return 0; 315 | } 316 | // ==================================================================================== 317 | public int Close() 318 | { 319 | DoDisconnect(); 320 | return 0; 321 | } 322 | // ==================================================================================== 323 | public async Task SetBitDevice(string iDeviceName, int iSize, int[] iData) 324 | { 325 | PlcDeviceType type; 326 | int addr; 327 | GetDeviceCode(iDeviceName, out type, out addr); 328 | return await SetBitDevice(type, addr, iSize, iData); 329 | } 330 | // ==================================================================================== 331 | public async Task SetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] iData) 332 | { 333 | var type = iType; 334 | var addr = iAddress; 335 | var data = new List(6) 336 | { 337 | (byte) addr 338 | , (byte) (addr >> 8) 339 | , (byte) (addr >> 16) 340 | , (byte) type 341 | , (byte) iSize 342 | , (byte) (iSize >> 8) 343 | }; 344 | var d = (byte)iData[0]; 345 | var i = 0; 346 | while (i < iData.Length) 347 | { 348 | if (i % 2 == 0) 349 | { 350 | d = (byte)iData[i]; 351 | d <<= 4; 352 | } 353 | else 354 | { 355 | d |= (byte)(iData[i] & 0x01); 356 | data.Add(d); 357 | } 358 | ++i; 359 | } 360 | if (i % 2 != 0) 361 | { 362 | data.Add(d); 363 | } 364 | int length = (int)Command.FrameType;// == McFrame.MC3E) ? 11 : 15; 365 | byte[] sdCommand = Command.SetCommandMC3E(0x1401, 0x0001, data.ToArray()); 366 | byte[] rtResponse = await TryExecution(sdCommand, length); 367 | int rtCode = Command.SetResponse(rtResponse); 368 | return rtCode; 369 | } 370 | // ==================================================================================== 371 | public async Task GetBitDevice(string iDeviceName, int iSize, int[] oData) 372 | { 373 | PlcDeviceType type; 374 | int addr; 375 | GetDeviceCode(iDeviceName, out type, out addr); 376 | return await GetBitDevice(type, addr, iSize, oData); 377 | } 378 | // ==================================================================================== 379 | public async Task GetBitDevice(PlcDeviceType iType, int iAddress, int iSize, int[] oData) 380 | { 381 | 382 | PlcDeviceType type = iType; 383 | int addr = iAddress; 384 | var data = new List(6) 385 | { 386 | (byte) addr 387 | , (byte) (addr >> 8) 388 | , (byte) (addr >> 16) 389 | , (byte) type 390 | , (byte) iSize 391 | , (byte) (iSize >> 8) 392 | }; 393 | byte[] sdCommand = Command.SetCommandMC3E(0x0401, 0x0001, data.ToArray()); 394 | int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; 395 | byte[] rtResponse = await TryExecution(sdCommand, length); 396 | int rtCode = Command.SetResponse(rtResponse); 397 | byte[] rtData = Command.Response; 398 | for (int i = 0; i < iSize; ++i) 399 | { 400 | if (i % 2 == 0) 401 | { 402 | oData[i] = (rtCode == 0) ? ((rtData[i / 2] >> 4) & 0x01) : 0; 403 | } 404 | else 405 | { 406 | oData[i] = (rtCode == 0) ? (rtData[i / 2] & 0x01) : 0; 407 | } 408 | } 409 | return rtCode; 410 | } 411 | // ==================================================================================== 412 | public async Task WriteDeviceBlock(string iDeviceName, int iSize, int[] iData) 413 | { 414 | PlcDeviceType type; 415 | int addr; 416 | GetDeviceCode(iDeviceName, out type, out addr); 417 | return await WriteDeviceBlock(type, addr, iSize, iData); 418 | } 419 | // ==================================================================================== 420 | public async Task WriteDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, int[] iData) 421 | { 422 | 423 | PlcDeviceType type = iType; 424 | int addr = iAddress; 425 | List data; 426 | 427 | List DeviceData = new List(); 428 | foreach (int t in iData) 429 | { 430 | DeviceData.Add((byte)t); 431 | DeviceData.Add((byte)(t >> 8)); 432 | } 433 | 434 | byte[] sdCommand; 435 | int length; 436 | //TEST Create this write switch statement 437 | switch (CommandFrame) 438 | { 439 | case McFrame.MC3E: 440 | data = new List(6) 441 | { 442 | (byte) addr 443 | , (byte) (addr >> 8) 444 | , (byte) (addr >> 16) 445 | , (byte) type 446 | , (byte) iSize 447 | , (byte) (iSize >> 8) 448 | }; 449 | data.AddRange(DeviceData.ToArray()); 450 | sdCommand = Command.SetCommandMC3E(0x1401, 0x0000, data.ToArray()); 451 | length = 11; 452 | break; 453 | case McFrame.MC4E: 454 | data = new List(6) 455 | { 456 | (byte) addr 457 | , (byte) (addr >> 8) 458 | , (byte) (addr >> 16) 459 | , (byte) type 460 | , (byte) iSize 461 | , (byte) (iSize >> 8) 462 | }; 463 | data.AddRange(DeviceData.ToArray()); 464 | sdCommand = Command.SetCommandMC4E(0x1401, 0x0000, data.ToArray()); 465 | length = 15; 466 | break; 467 | case McFrame.MC1E: 468 | data = new List(6) 469 | { 470 | (byte) addr 471 | , (byte) (addr >> 8) 472 | , (byte) (addr >> 16) 473 | , (byte) (addr >> 24) 474 | , 0x20 475 | , 0x44 476 | , (byte) iSize 477 | , 0x00 478 | }; 479 | data.AddRange(DeviceData.ToArray()); 480 | //Add data 481 | sdCommand = Command.SetCommandMC1E(0x03, data.ToArray()); 482 | length = 2; 483 | break; 484 | default: 485 | throw new Exception("Message frame not supported"); 486 | } 487 | 488 | //TEST take care of the writing 489 | byte[] rtResponse = await TryExecution(sdCommand, length); 490 | int rtCode = Command.SetResponse(rtResponse); 491 | return rtCode; 492 | } 493 | public async Task WriteDeviceBlock(PlcDeviceType iType, int iAddress, int devicePoints, byte[] bData) 494 | { 495 | //FIXME 496 | int iSize = devicePoints; 497 | PlcDeviceType type = iType; 498 | int addr = iAddress; 499 | List data; 500 | byte[] sdCommand; 501 | int length; 502 | //TEST Create this write switch statement 503 | switch (CommandFrame) 504 | { 505 | case McFrame.MC3E: 506 | data = new List(6) 507 | { 508 | (byte) addr 509 | , (byte) (addr >> 8) 510 | , (byte) (addr >> 16) 511 | , (byte) type 512 | , (byte) iSize 513 | , (byte) (iSize >> 8) 514 | }; 515 | data.AddRange(bData); 516 | sdCommand = Command.SetCommandMC3E(0x1401, 0x0000, data.ToArray()); 517 | length = 11; 518 | break; 519 | case McFrame.MC4E: 520 | data = new List(6) 521 | { 522 | (byte) addr 523 | , (byte) (addr >> 8) 524 | , (byte) (addr >> 16) 525 | , (byte) type 526 | , (byte) iSize 527 | , (byte) (iSize >> 8) 528 | }; 529 | data.AddRange(bData); 530 | sdCommand = Command.SetCommandMC4E(0x1401, 0x0000, data.ToArray()); 531 | length = 15; 532 | break; 533 | case McFrame.MC1E: 534 | data = new List(6) 535 | { 536 | (byte) addr 537 | , (byte) (addr >> 8) 538 | , (byte) (addr >> 16) 539 | , (byte) (addr >> 24) 540 | , 0x20 541 | , 0x44 542 | , (byte) iSize 543 | , 0x00 544 | }; 545 | data.AddRange(bData); 546 | //Add data 547 | sdCommand = Command.SetCommandMC1E(0x03, data.ToArray()); 548 | length = 2; 549 | break; 550 | default: 551 | throw new Exception("Message frame not supported"); 552 | } 553 | //TEST take care of the writing 554 | byte[] rtResponse = await TryExecution(sdCommand, length); 555 | int rtCode = Command.SetResponse(rtResponse); 556 | return rtCode; 557 | } 558 | // ==================================================================================== 559 | public async Task ReadDeviceBlock(string iDeviceName, int iSize, int[] oData) 560 | { 561 | PlcDeviceType type; 562 | int addr; 563 | GetDeviceCode(iDeviceName, out type, out addr); 564 | return await ReadDeviceBlock(type, addr, iSize, oData); 565 | } 566 | // ==================================================================================== 567 | public async Task ReadDeviceBlock(PlcDeviceType iType, int iAddress, int iSize, int[] oData) 568 | { 569 | 570 | PlcDeviceType type = iType; 571 | int addr = iAddress; 572 | List data; 573 | byte[] sdCommand; 574 | int length; 575 | 576 | switch (CommandFrame) 577 | { 578 | case McFrame.MC3E: 579 | data = new List(6) 580 | { 581 | (byte) addr 582 | , (byte) (addr >> 8) 583 | , (byte) (addr >> 16) 584 | , (byte) type 585 | , (byte) iSize 586 | , (byte) (iSize >> 8) 587 | }; 588 | sdCommand = Command.SetCommandMC3E(0x0401, 0x0000, data.ToArray()); 589 | length = 11; 590 | break; 591 | case McFrame.MC4E: 592 | data = new List(6) 593 | { 594 | (byte) addr 595 | , (byte) (addr >> 8) 596 | , (byte) (addr >> 16) 597 | , (byte) type 598 | , (byte) iSize 599 | , (byte) (iSize >> 8) 600 | }; 601 | sdCommand = Command.SetCommandMC4E(0x0401, 0x0000, data.ToArray()); 602 | length = 15; 603 | break; 604 | case McFrame.MC1E: 605 | data = new List(6) 606 | { 607 | (byte) addr 608 | , (byte) (addr >> 8) 609 | , (byte) (addr >> 16) 610 | , (byte) (addr >> 24) 611 | , 0x20 612 | , 0x44 613 | , (byte) iSize 614 | , 0x00 615 | }; 616 | sdCommand = Command.SetCommandMC1E(0x01, data.ToArray()); 617 | length = 2; 618 | break; 619 | default: 620 | throw new Exception("Message frame not supported"); 621 | } 622 | 623 | byte[] rtResponse = await TryExecution(sdCommand, length); 624 | //TEST verify read responses 625 | int rtCode = Command.SetResponse(rtResponse); 626 | byte[] rtData = Command.Response; 627 | for (int i = 0; i < iSize; ++i) 628 | { 629 | oData[i] = (rtCode == 0) ? BitConverter.ToInt16(rtData, i * 2) : 0; 630 | } 631 | return rtData; 632 | } 633 | public async Task ReadDeviceBlock(PlcDeviceType iType, int iAddress, int devicePoints) 634 | { 635 | int iSize = devicePoints; 636 | PlcDeviceType type = iType; 637 | int addr = iAddress; 638 | List data; 639 | byte[] sdCommand; 640 | int length; 641 | 642 | switch (CommandFrame) 643 | { 644 | case McFrame.MC3E: 645 | data = new List(6) 646 | { 647 | (byte) addr 648 | , (byte) (addr >> 8) 649 | , (byte) (addr >> 16) 650 | , (byte) type 651 | , (byte) iSize 652 | , (byte) (iSize >> 8) 653 | }; 654 | sdCommand = Command.SetCommandMC3E(0x0401, 0x0000, data.ToArray()); 655 | length = 11; 656 | break; 657 | case McFrame.MC4E: 658 | data = new List(6) 659 | { 660 | (byte) addr 661 | , (byte) (addr >> 8) 662 | , (byte) (addr >> 16) 663 | , (byte) type 664 | , (byte) iSize 665 | , (byte) (iSize >> 8) 666 | }; 667 | sdCommand = Command.SetCommandMC4E(0x0401, 0x0000, data.ToArray()); 668 | length = 15; 669 | break; 670 | case McFrame.MC1E: 671 | data = new List(6) 672 | { 673 | (byte) addr 674 | , (byte) (addr >> 8) 675 | , (byte) (addr >> 16) 676 | , (byte) (addr >> 24) 677 | , 0x20 678 | , 0x44 679 | , (byte) iSize 680 | , 0x00 681 | }; 682 | sdCommand = Command.SetCommandMC1E(0x01, data.ToArray()); 683 | length = 2; 684 | break; 685 | default: 686 | throw new Exception("Message frame not supported"); 687 | } 688 | 689 | byte[] rtResponse = await TryExecution(sdCommand, length); 690 | //TEST verify read responses 691 | int rtCode = Command.SetResponse(rtResponse); 692 | byte[] rtData = Command.Response; 693 | return rtData; 694 | } 695 | // ==================================================================================== 696 | public async Task SetDevice(string iDeviceName, int iData) 697 | { 698 | PlcDeviceType type; 699 | int addr; 700 | GetDeviceCode(iDeviceName, out type, out addr); 701 | return await SetDevice(type, addr, iData); 702 | } 703 | // ==================================================================================== 704 | public async Task SetDevice(PlcDeviceType iType, int iAddress, int iData) 705 | { 706 | 707 | PlcDeviceType type = iType; 708 | int addr = iAddress; 709 | var data = new List(6) 710 | { 711 | (byte) addr 712 | , (byte) (addr >> 8) 713 | , (byte) (addr >> 16) 714 | , (byte) type 715 | , 0x01 716 | , 0x00 717 | , (byte) iData 718 | , (byte) (iData >> 8) 719 | }; 720 | byte[] sdCommand = Command.SetCommandMC3E(0x1401, 0x0000, data.ToArray()); 721 | int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; 722 | byte[] rtResponse = await TryExecution(sdCommand, length); 723 | int rtCode = Command.SetResponse(rtResponse); 724 | return rtCode; 725 | } 726 | // ==================================================================================== 727 | public async Task GetDevice(string iDeviceName) 728 | { 729 | PlcDeviceType type; 730 | int addr; 731 | GetDeviceCode(iDeviceName, out type, out addr); 732 | return await GetDevice(type, addr); 733 | } 734 | // ==================================================================================== 735 | public async Task GetDevice(PlcDeviceType iType, int iAddress) 736 | { 737 | PlcDeviceType type = iType; 738 | int addr = iAddress; 739 | var data = new List(6) 740 | { 741 | (byte) addr 742 | , (byte) (addr >> 8) 743 | , (byte) (addr >> 16) 744 | , (byte) type 745 | , 0x01 746 | , 0x00 747 | }; 748 | byte[] sdCommand = Command.SetCommandMC3E(0x0401, 0x0000, data.ToArray()); 749 | int length = (Command.FrameType == McFrame.MC3E) ? 11 : 15; 750 | ; byte[] rtResponse = await TryExecution(sdCommand, length); 751 | int rtCode = Command.SetResponse(rtResponse); 752 | if (0 < rtCode) 753 | { 754 | this.Device = 0; 755 | } 756 | else 757 | { 758 | byte[] rtData = Command.Response; 759 | this.Device = BitConverter.ToInt16(rtData, 0); 760 | } 761 | return rtCode; 762 | } 763 | // ==================================================================================== 764 | //public int GetCpuType(out string oCpuName, out int oCpuType) 765 | //{ 766 | // int rtCode = Command.Execute(0x0101, 0x0000, new byte[0]); 767 | // oCpuName = "dummy"; 768 | // oCpuType = 0; 769 | // return rtCode; 770 | //} 771 | // ==================================================================================== 772 | public static PlcDeviceType GetDeviceType(string s) 773 | { 774 | return (s == "M") ? PlcDeviceType.M : 775 | (s == "SM") ? PlcDeviceType.SM : 776 | (s == "L") ? PlcDeviceType.L : 777 | (s == "F") ? PlcDeviceType.F : 778 | (s == "V") ? PlcDeviceType.V : 779 | (s == "S") ? PlcDeviceType.S : 780 | (s == "X") ? PlcDeviceType.X : 781 | (s == "Y") ? PlcDeviceType.Y : 782 | (s == "B") ? PlcDeviceType.B : 783 | (s == "SB") ? PlcDeviceType.SB : 784 | (s == "DX") ? PlcDeviceType.DX : 785 | (s == "DY") ? PlcDeviceType.DY : 786 | (s == "D") ? PlcDeviceType.D : 787 | (s == "SD") ? PlcDeviceType.SD : 788 | (s == "R") ? PlcDeviceType.R : 789 | (s == "ZR") ? PlcDeviceType.ZR : 790 | (s == "W") ? PlcDeviceType.W : 791 | (s == "SW") ? PlcDeviceType.SW : 792 | (s == "TC") ? PlcDeviceType.TC : 793 | (s == "TS") ? PlcDeviceType.TS : 794 | (s == "TN") ? PlcDeviceType.TN : 795 | (s == "CC") ? PlcDeviceType.CC : 796 | (s == "CS") ? PlcDeviceType.CS : 797 | (s == "CN") ? PlcDeviceType.CN : 798 | (s == "SC") ? PlcDeviceType.SC : 799 | (s == "SS") ? PlcDeviceType.SS : 800 | (s == "SN") ? PlcDeviceType.SN : 801 | (s == "Z") ? PlcDeviceType.Z : 802 | (s == "TT") ? PlcDeviceType.TT : 803 | (s == "TM") ? PlcDeviceType.TM : 804 | (s == "CT") ? PlcDeviceType.CT : 805 | (s == "CM") ? PlcDeviceType.CM : 806 | (s == "A") ? PlcDeviceType.A : 807 | PlcDeviceType.Max; 808 | } 809 | 810 | // ==================================================================================== 811 | public static bool IsBitDevice(PlcDeviceType type) 812 | { 813 | return !((type == PlcDeviceType.D) 814 | || (type == PlcDeviceType.SD) 815 | || (type == PlcDeviceType.Z) 816 | || (type == PlcDeviceType.ZR) 817 | || (type == PlcDeviceType.R) 818 | || (type == PlcDeviceType.W)); 819 | } 820 | 821 | // ==================================================================================== 822 | public static bool IsHexDevice(PlcDeviceType type) 823 | { 824 | return (type == PlcDeviceType.X) 825 | || (type == PlcDeviceType.Y) 826 | || (type == PlcDeviceType.B) 827 | || (type == PlcDeviceType.W); 828 | } 829 | 830 | // ==================================================================================== 831 | public static void GetDeviceCode(string iDeviceName, out PlcDeviceType oType, out int oAddress) 832 | { 833 | string s = iDeviceName.ToUpper(); 834 | string strAddress; 835 | 836 | // 1文字取り出す 837 | string strType = s.Substring(0, 1); 838 | switch (strType) 839 | { 840 | case "A": 841 | case "B": 842 | case "D": 843 | case "F": 844 | case "L": 845 | case "M": 846 | case "R": 847 | case "V": 848 | case "W": 849 | case "X": 850 | case "Y": 851 | // 2文字目以降は数値のはずなので変換する 852 | strAddress = s.Substring(1); 853 | break; 854 | case "Z": 855 | // もう1文字取り出す 856 | strType = s.Substring(0, 2); 857 | // ファイルレジスタの場合 : 2 858 | // インデックスレジスタの場合 : 1 859 | strAddress = s.Substring(strType.Equals("ZR") ? 2 : 1); 860 | break; 861 | case "C": 862 | // もう1文字取り出す 863 | strType = s.Substring(0, 2); 864 | switch (strType) 865 | { 866 | case "CC": 867 | case "CM": 868 | case "CN": 869 | case "CS": 870 | case "CT": 871 | strAddress = s.Substring(2); 872 | break; 873 | default: 874 | throw new Exception("Invalid format."); 875 | } 876 | break; 877 | case "S": 878 | // もう1文字取り出す 879 | strType = s.Substring(0, 2); 880 | switch (strType) 881 | { 882 | case "SD": 883 | case "SM": 884 | strAddress = s.Substring(2); 885 | break; 886 | default: 887 | throw new Exception("Invalid format."); 888 | } 889 | break; 890 | case "T": 891 | // もう1文字取り出す 892 | strType = s.Substring(0, 2); 893 | switch (strType) 894 | { 895 | case "TC": 896 | case "TM": 897 | case "TN": 898 | case "TS": 899 | case "TT": 900 | strAddress = s.Substring(2); 901 | break; 902 | default: 903 | throw new Exception("Invalid format."); 904 | } 905 | break; 906 | default: 907 | throw new Exception("Invalid format."); 908 | } 909 | 910 | oType = GetDeviceType(strType); 911 | oAddress = IsHexDevice(oType) ? Convert.ToInt32(strAddress, BlockSize) : 912 | Convert.ToInt32(strAddress); 913 | } 914 | // &&&&& protected &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 915 | abstract protected Task DoConnect(); 916 | abstract protected void DoDisconnect(); 917 | abstract protected Task Execute(byte[] iCommand); 918 | // &&&&& private &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 919 | private const int BlockSize = 0x0010; 920 | private McCommand Command { get; set; } 921 | 922 | 923 | 924 | // ================================================================================ 925 | private async Task TryExecution(byte[] iCommand, int minlength) 926 | { 927 | 928 | byte[] rtResponse; 929 | int tCount = 10; 930 | do 931 | { 932 | rtResponse = await Execute(iCommand); 933 | --tCount; 934 | if (tCount < 0) 935 | { 936 | throw new Exception("PLCから正しい値が取得できません."); 937 | } 938 | } while (Command.IsIncorrectResponse(rtResponse, minlength)); 939 | return rtResponse; 940 | } 941 | // #################################################################################### 942 | // 通信に使用するコマンドを表現するインナークラス 943 | class McCommand 944 | { 945 | public McFrame FrameType { get; private set; } // フレーム種別 946 | private uint SerialNumber { get; set; } // シリアル番号 947 | private uint NetworkNumber { get; set; } // ネットワーク番号 948 | private uint PcNumber { get; set; } // PC番号 949 | private uint IoNumber { get; set; } // 要求先ユニットI/O番号 950 | private uint ChannelNumber { get; set; } // 要求先ユニット局番号 951 | private uint CpuTimer { get; set; } // CPU監視タイマ 952 | private int ResultCode { get; set; } // 終了コード 953 | public byte[] Response { get; private set; } // 応答データ 954 | // ================================================================================ 955 | // コンストラクタ 956 | public McCommand(McFrame iFrame) 957 | { 958 | FrameType = iFrame; 959 | SerialNumber = 0x0001u; 960 | NetworkNumber = 0x0000u; 961 | PcNumber = 0x00FFu; 962 | IoNumber = 0x03FFu; 963 | ChannelNumber = 0x0000u; 964 | CpuTimer = 0x0010u; 965 | } 966 | // ================================================================================ 967 | public byte[] SetCommandMC1E(byte Subheader, byte[] iData) 968 | { 969 | List ret = new List(iData.Length + 4); 970 | ret.Add(Subheader); 971 | ret.Add((byte)this.PcNumber); 972 | ret.Add((byte)CpuTimer); 973 | ret.Add((byte)(CpuTimer >> 8)); 974 | ret.AddRange(iData); 975 | return ret.ToArray(); 976 | } 977 | public byte[] SetCommandMC3E(uint iMainCommand, uint iSubCommand, byte[] iData) 978 | { 979 | var dataLength = (uint)(iData.Length + 6); 980 | List ret = new List(iData.Length + 20); 981 | uint frame = 0x0050u; 982 | ret.Add((byte)frame); 983 | ret.Add((byte)(frame >> 8)); 984 | 985 | ret.Add((byte)NetworkNumber); 986 | 987 | ret.Add((byte)PcNumber); 988 | 989 | ret.Add((byte)IoNumber); 990 | ret.Add((byte)(IoNumber >> 8)); 991 | ret.Add((byte)ChannelNumber); 992 | ret.Add((byte)dataLength); 993 | ret.Add((byte)(dataLength >> 8)); 994 | 995 | 996 | ret.Add((byte)CpuTimer); 997 | ret.Add((byte)(CpuTimer >> 8)); 998 | ret.Add((byte)iMainCommand); 999 | ret.Add((byte)(iMainCommand >> 8)); 1000 | ret.Add((byte)iSubCommand); 1001 | ret.Add((byte)(iSubCommand >> 8)); 1002 | 1003 | ret.AddRange(iData); 1004 | return ret.ToArray(); 1005 | } 1006 | public byte[] SetCommandMC4E(uint iMainCommand, uint iSubCommand, byte[] iData) 1007 | { 1008 | var dataLength = (uint)(iData.Length + 6); 1009 | var ret = new List(iData.Length + 20); 1010 | uint frame = 0x0054u; 1011 | ret.Add((byte)frame); 1012 | ret.Add((byte)(frame >> 8)); 1013 | ret.Add((byte)SerialNumber); 1014 | ret.Add((byte)(SerialNumber >> 8)); 1015 | ret.Add(0x00); 1016 | ret.Add(0x00); 1017 | ret.Add((byte)NetworkNumber); 1018 | ret.Add((byte)PcNumber); 1019 | ret.Add((byte)IoNumber); 1020 | ret.Add((byte)(IoNumber >> 8)); 1021 | ret.Add((byte)ChannelNumber); 1022 | ret.Add((byte)dataLength); 1023 | ret.Add((byte)(dataLength >> 8)); 1024 | ret.Add((byte)CpuTimer); 1025 | ret.Add((byte)(CpuTimer >> 8)); 1026 | ret.Add((byte)iMainCommand); 1027 | ret.Add((byte)(iMainCommand >> 8)); 1028 | ret.Add((byte)iSubCommand); 1029 | ret.Add((byte)(iSubCommand >> 8)); 1030 | 1031 | ret.AddRange(iData); 1032 | return ret.ToArray(); 1033 | } 1034 | // ================================================================================ 1035 | public int SetResponse(byte[] iResponse) 1036 | { 1037 | int min; 1038 | switch (FrameType) 1039 | { 1040 | case McFrame.MC1E: 1041 | min = 2; 1042 | if (min <= iResponse.Length) 1043 | { 1044 | //There is a subheader, end code and data. 1045 | 1046 | ResultCode = (int)iResponse[min - 2]; 1047 | Response = new byte[iResponse.Length - 2]; 1048 | Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); 1049 | } 1050 | break; 1051 | case McFrame.MC3E: 1052 | min = 11; 1053 | if (min <= iResponse.Length) 1054 | { 1055 | var btCount = new[] { iResponse[min - 4], iResponse[min - 3] }; 1056 | var btCode = new[] { iResponse[min - 2], iResponse[min - 1] }; 1057 | int rsCount = BitConverter.ToUInt16(btCount, 0); 1058 | ResultCode = BitConverter.ToUInt16(btCode, 0); 1059 | Response = new byte[rsCount - 2]; 1060 | Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); 1061 | } 1062 | break; 1063 | case McFrame.MC4E: 1064 | min = 15; 1065 | if (min <= iResponse.Length) 1066 | { 1067 | var btCount = new[] { iResponse[min - 4], iResponse[min - 3] }; 1068 | var btCode = new[] { iResponse[min - 2], iResponse[min - 1] }; 1069 | int rsCount = BitConverter.ToUInt16(btCount, 0); 1070 | ResultCode = BitConverter.ToUInt16(btCode, 0); 1071 | Response = new byte[rsCount - 2]; 1072 | Buffer.BlockCopy(iResponse, min, Response, 0, Response.Length); 1073 | } 1074 | break; 1075 | default: 1076 | throw new Exception("Frame type not supported."); 1077 | 1078 | } 1079 | return ResultCode; 1080 | } 1081 | // ================================================================================ 1082 | public bool IsIncorrectResponse(byte[] iResponse, int minLenght) 1083 | { 1084 | //TEST add 1E frame 1085 | switch (this.FrameType) 1086 | { 1087 | case McFrame.MC1E: 1088 | return ((iResponse.Length < minLenght)); 1089 | 1090 | case McFrame.MC3E: 1091 | case McFrame.MC4E: 1092 | var btCount = new[] { iResponse[minLenght - 4], iResponse[minLenght - 3] }; 1093 | var btCode = new[] { iResponse[minLenght - 2], iResponse[minLenght - 1] }; 1094 | var rsCount = BitConverter.ToUInt16(btCount, 0) - 2; 1095 | var rsCode = BitConverter.ToUInt16(btCode, 0); 1096 | return (rsCode == 0 && rsCount != (iResponse.Length - minLenght)); 1097 | 1098 | default: 1099 | throw new Exception("Type Not supported"); 1100 | 1101 | } 1102 | } 1103 | } 1104 | } 1105 | 1106 | // ######################################################################################## 1107 | public class McProtocolTcp : McProtocolApp 1108 | { 1109 | // ==================================================================================== 1110 | // コンストラクタ 1111 | public override bool Connected 1112 | { 1113 | get 1114 | { 1115 | return Client.Connected; 1116 | } 1117 | } 1118 | public McProtocolTcp() : this("", 0, McFrame.MC3E) { } 1119 | public McProtocolTcp(string iHostName, int iPortNumber, McFrame frame) 1120 | : base(iHostName, iPortNumber, frame) 1121 | { 1122 | CommandFrame = frame; 1123 | #if !old 1124 | this.Host = new HostName(iHostName); 1125 | 1126 | this.streamSocket = new StreamSocket(); 1127 | 1128 | this.Port = iPortNumber; 1129 | #endif 1130 | Client = new TcpClient(); 1131 | } 1132 | 1133 | // &&&&& protected &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1134 | async override protected Task DoConnect() 1135 | { 1136 | #if !old 1137 | this.streamSocket.Control.KeepAlive = true; 1138 | 1139 | await this.streamSocket.ConnectAsync(this.Host, "" + this.Port); 1140 | #endif 1141 | #if old 1142 | //TcpClient c = Client; 1143 | if (!Client.Connected) 1144 | { 1145 | // Keep Alive機能の実装 1146 | var ka = new List(sizeof(uint) * 3); 1147 | ka.AddRange(BitConverter.GetBytes(1u)); 1148 | ka.AddRange(BitConverter.GetBytes(45000u)); 1149 | ka.AddRange(BitConverter.GetBytes(5000u)); 1150 | Client.Client.IOControl(IOControlCode.KeepAliveValues, ka.ToArray(), null); 1151 | Client.Connect(HostName, PortNumber); 1152 | Stream = Client.GetStream(); 1153 | 1154 | } 1155 | #endif 1156 | return 0; 1157 | } 1158 | // ==================================================================================== 1159 | override protected void DoDisconnect() 1160 | { 1161 | #if !old 1162 | this.streamSocket.Dispose(); 1163 | #endif 1164 | #if old 1165 | TcpClient c = Client; 1166 | if (c.Connected) 1167 | { 1168 | c.Close(); 1169 | } 1170 | #endif 1171 | } 1172 | // ================================================================================ 1173 | async override protected Task Execute(byte[] iCommand) 1174 | { 1175 | List list = new List(); 1176 | #if windows 1177 | 1178 | //Write to the buffer 1179 | 1180 | 1181 | await this.streamSocket.CancelIOAsync(); 1182 | 1183 | Windows.Storage.Streams.DataWriter writer = new Windows.Storage.Streams.DataWriter(this.streamSocket.OutputStream); 1184 | writer.WriteBytes(iCommand); 1185 | await writer.StoreAsync(); 1186 | writer.DetachStream(); 1187 | 1188 | 1189 | //Read back from the buffer 1190 | 1191 | Windows.Storage.Streams.DataReader reader = new Windows.Storage.Streams.DataReader(this.streamSocket.InputStream); 1192 | reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial; 1193 | reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; 1194 | reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; 1195 | //Load 4 bytes off the buffer as the header 1196 | //DONE Fix the read length 1197 | //do 1198 | //{ 1199 | await reader.LoadAsync(256); 1200 | //if (reader.UnconsumedBufferLength == 0) break; 1201 | byte[] bytes = new byte[reader.UnconsumedBufferLength]; 1202 | reader.ReadBytes(bytes);//Should be 4 1203 | list.AddRange(bytes); 1204 | reader.DetachStream(); 1205 | //} while (true); 1206 | return list.ToArray(); 1207 | #endif 1208 | 1209 | #if old 1210 | 1211 | #endif 1212 | #if reading 1213 | await reader.LoadAsync(header[header.Length - 1]);//The last byte should be the remaining lenght 1214 | // 1215 | byte[] data = new byte[reader.UnconsumedBufferLength]; 1216 | reader.ReadBytes(data); 1217 | byte[] buffer = new byte[header.Length + data.Length]; 1218 | header.CopyTo(buffer, 0); 1219 | data.CopyTo(buffer, header.Length); 1220 | 1221 | #else 1222 | 1223 | 1224 | #endif 1225 | 1226 | 1227 | 1228 | #if old 1229 | 1230 | NetworkStream ns = Stream; 1231 | ns.Write(iCommand, 0, iCommand.Length); 1232 | ns.Flush(); 1233 | 1234 | using (var ms = new MemoryStream()) 1235 | { 1236 | var buff = new byte[256]; 1237 | do 1238 | { 1239 | int sz = ns.Read(buff, 0, buff.Length); 1240 | if (sz == 0) 1241 | { 1242 | throw new Exception("切断されました"); 1243 | } 1244 | ms.Write(buff, 0, sz); 1245 | } while (ns.DataAvailable); 1246 | return ms.ToArray(); 1247 | } 1248 | #endif 1249 | 1250 | } 1251 | // &&&&& private &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1252 | #if !old 1253 | private HostName Host { get; set; } 1254 | private StreamSocket streamSocket { get; set; } 1255 | private int Port { get; set; } 1256 | #endif 1257 | #if old 1258 | private TcpClient Client { get; set; } 1259 | private NetworkStream Stream { get; set; } 1260 | #endif 1261 | } 1262 | #if udp 1263 | // ######################################################################################## 1264 | public class McProtocolUdp : McProtocolApp 1265 | { 1266 | // ==================================================================================== 1267 | // コンストラクタ 1268 | public McProtocolUdp(int iPortNumber) : this("", iPortNumber) { } 1269 | public McProtocolUdp(string iHostName, int iPortNumber) 1270 | : base(iHostName, iPortNumber) 1271 | { 1272 | Client = new UdpClient(iPortNumber); 1273 | } 1274 | 1275 | // &&&&& protected &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1276 | override protected void DoConnect() 1277 | { 1278 | UdpClient c = Client; 1279 | c.Connect(HostName, PortNumber); 1280 | } 1281 | // ==================================================================================== 1282 | override protected void DoDisconnect() 1283 | { 1284 | // UDPでは何もしない 1285 | } 1286 | // ================================================================================ 1287 | override protected byte[] Execute(byte[] iCommand) 1288 | { 1289 | UdpClient c = Client; 1290 | // 送信 1291 | c.Send(iCommand, iCommand.Length); 1292 | 1293 | using (var ms = new MemoryStream()) 1294 | { 1295 | IPAddress ip = IPAddress.Parse(HostName); 1296 | var ep = new IPEndPoint(ip, PortNumber); 1297 | do 1298 | { 1299 | // 受信 1300 | byte[] buff = c.Receive(ref ep); 1301 | ms.Write(buff, 0, buff.Length); 1302 | } while (0 < c.Available); 1303 | return ms.ToArray(); 1304 | } 1305 | } 1306 | // &&&&& private &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1307 | private UdpClient Client { get; set; } 1308 | } 1309 | #endif 1310 | } 1311 | } 1312 | 1313 | 1314 | -------------------------------------------------------------------------------- /McProtocol/McProtocol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | true 6 | 1.2.5.0 7 | 1.2.5.0 8 | 1.2.5 9 | Luke Mehringer 10 | false 11 | https://www.gnu.org/licenses/lgpl-3.0.en.html 12 | Luke Mehringer 13 | 14 | 15 | 16 | --------------------------------------------------------------------------------