plc_access 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f4f7913359b4f1b4f637c20481709661b056a264b76280ffe8a0948d2bbe1a3
4
- data.tar.gz: b126188a9c855a3f2dd9a368edc32d022daf5b03274d0f4201aa34ee3dbff5ee
3
+ metadata.gz: c7944febc355a406f20d64952237fb1cb58d718c079d9b1743535ce495d5a153
4
+ data.tar.gz: d76735035b4e7749ef4beb234b5cad4392090fe892ae6321a3ae24e14a54cc25
5
5
  SHA512:
6
- metadata.gz: dbca94f874f0a4792036f4bb99d46ff71f1d0360666c81bcef68b80fa9fad7cf3c272e2d5fa7d624409c80167715f928e5c53c95db8bdbf1f5f94c297a33ba62
7
- data.tar.gz: 117d893285cc51e0de947495ac02b5e3348b6bf818ad1d7d20c1a77ad935fd56472d747922ebd3f9836331ff2d10d540e7aa7877374136689637515e4c7d024d
6
+ metadata.gz: a8a256b8f7e4cf5d3a7e1cbf6d7d21168ceaccb0927279c1427f293bb603622b648ae1d660649262d10204f8146f926d9f7ec6cf8ec38a2ae6089c475b0f4d39
7
+ data.tar.gz: 7d5e7fc1ca634bb9397f4f752b91efa4eecdc3535db7915e01f3e3a0f9b06b57ec250f8d69c4eafba5afbc313d30d17b2f1db629eaef66b15348dbf3da9ea6fa
data/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # CHANGES
2
2
 
3
+ ## 0.2.1
4
+
5
+ - Add byte order support for string/ushort conversion per PLC type (Mitsubishi: little-endian, Keyence/Omron: big-endian)
6
+ - Accept plc object in as_ushort/to_string to auto-detect byte order
7
+ - Allow Protocol#[]= to pad with zeros or truncate when array size differs from count
8
+ - Allow Protocol#[]= to accept arrays without specifying count
9
+
3
10
  ## 0.1.3
4
11
 
5
12
  - Rename Array#as_string to Array#to_string
data/Gemfile.lock CHANGED
@@ -1,43 +1,49 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plc_access (0.1.1)
4
+ plc_access (0.2.1)
5
5
  serialport (~> 1.3, >= 1.3.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  ast (2.4.2)
11
- json (2.6.2)
12
- parallel (1.22.1)
13
- parser (3.1.2.1)
11
+ json (2.18.1)
12
+ language_server-protocol (3.17.0.4)
13
+ lint_roller (1.1.0)
14
+ parallel (1.26.3)
15
+ parser (3.3.7.1)
14
16
  ast (~> 2.4.1)
15
- power_assert (2.0.1)
17
+ racc
18
+ power_assert (2.0.5)
19
+ racc (1.8.1)
16
20
  rainbow (3.1.1)
17
21
  rake (12.3.3)
18
- regexp_parser (2.5.0)
19
- rexml (3.2.5)
20
- rr (3.1.0)
21
- rubocop (1.36.0)
22
+ regexp_parser (2.10.0)
23
+ rr (3.1.1)
24
+ rubocop (1.72.2)
22
25
  json (~> 2.3)
26
+ language_server-protocol (~> 3.17.0.2)
27
+ lint_roller (~> 1.1.0)
23
28
  parallel (~> 1.10)
24
- parser (>= 3.1.2.1)
29
+ parser (>= 3.3.0.2)
25
30
  rainbow (>= 2.2.2, < 4.0)
26
- regexp_parser (>= 1.8, < 3.0)
27
- rexml (>= 3.2.5, < 4.0)
28
- rubocop-ast (>= 1.20.1, < 2.0)
31
+ regexp_parser (>= 2.9.3, < 3.0)
32
+ rubocop-ast (>= 1.38.0, < 2.0)
29
33
  ruby-progressbar (~> 1.7)
30
- unicode-display_width (>= 1.4.0, < 3.0)
31
- rubocop-ast (1.21.0)
32
- parser (>= 3.1.1.0)
33
- ruby-progressbar (1.11.0)
34
+ unicode-display_width (>= 2.4.0, < 4.0)
35
+ rubocop-ast (1.38.0)
36
+ parser (>= 3.3.1.0)
37
+ ruby-progressbar (1.13.0)
34
38
  serialport (1.3.2)
35
- test-unit (3.5.3)
39
+ test-unit (3.6.7)
36
40
  power_assert
37
41
  test-unit-rr (1.0.5)
38
42
  rr (>= 1.1.1)
39
43
  test-unit (>= 2.5.2)
40
- unicode-display_width (2.3.0)
44
+ unicode-display_width (3.1.4)
45
+ unicode-emoji (~> 4.0, >= 4.0.4)
46
+ unicode-emoji (4.0.4)
41
47
 
42
48
  PLATFORMS
43
49
  ruby
data/README.md CHANGED
@@ -73,13 +73,88 @@ plc["DM0", 10] = [0, 1, 2, 3, 4].as_int # => [0, 0, 1, 0, 2, 0, 3, 0, 4, 0]
73
73
 
74
74
  plc["MR0", 10].to_int # => [0, 1, 2, 3, 4]
75
75
 
76
- # Set string to data memory (ten wors from DM0) as ushort values.
77
- plc["DM0", 10] = "PLC Access".as_ushort()
78
- # Get string from data memory (ten wors from DM0).
79
- plc["DM0", 10].to_string()
76
+ # Set string to data memory (ten words from DM0) as ushort values.
77
+ # The byte order for string conversion differs by PLC type
78
+ # (e.g., Mitsubishi uses little-endian, Keyence/Omron use big-endian).
79
+ # Pass plc to automatically use the correct byte order.
80
+ plc["DM0", 10] = "PLC Access".as_ushort(plc)
81
+ # Get string from data memory (ten words from DM0).
82
+ plc["DM0", 10].to_string(plc)
83
+
84
+ # You can also specify the length and plc together.
85
+ plc["DM0", 5] = "PLC Access".as_ushort(10, plc)
86
+ plc["DM0", 5].to_string(10, plc)
80
87
 
81
88
  ```
82
89
 
90
+ ## Supported PLCs
91
+
92
+ ### Keyence
93
+
94
+ It supports Keyence PLCs with an Ethernet connection.
95
+
96
+ ```
97
+ plc = PlcAccess::Protocol::Keyence::KvProtocol.new host: '192.168.0.10', port: 8501
98
+ ```
99
+
100
+ ### Mitsubishi
101
+
102
+ It supports Mitsubishi PLCs with an Ethernet connection.
103
+
104
+ ```
105
+ plc = PlcAccess::Protocol::Mitsubishi::McProtocol.new host: '192.168.0.10', port: 5010
106
+ ```
107
+
108
+ It supports Mitsubishi Fx PLCs with a Serial connection.
109
+
110
+ ```
111
+ plc = PlcAccess::Protocol::Mitsubishi::FxProtocol.new port: /dev/tty.usbxxxxx'
112
+ ```
113
+
114
+ PLC configuration:
115
+ - baudrate: 19200
116
+ - bit: 7
117
+ - parity: Odd
118
+ - stop bit: 1
119
+
120
+ ![](images/fx_comm_setting.png)
121
+
122
+ ### Omron
123
+
124
+ It supports Omron PLCs with an Ethernet connection.
125
+
126
+ ```
127
+ plc = PlcAccess::Protocol::Omron::FinsTcpProtocol.new host: '192.168.0.10', port: 9600
128
+ ```
129
+
130
+ It supports Omron PLCs with a C Mode serial connection.
131
+
132
+ ```
133
+ plc = PlcAccess::Protocol::Omron::CModeProtocol.new port: /dev/tty.usbxxxxx'
134
+ ```
135
+
136
+ ### Plc Share
137
+
138
+ Plc Share is a protocol conversion application. It runs on Windows and connects to various PLCs using a serial or Ethernet connection. You can then connect with the Plc Share Protocol, which extends Keyence’s protocol. You can specify a target PLC’s device.
139
+
140
+ [Plc Share](http://iphone.itosoft.com/plcshare)
141
+
142
+ ![](images/plc_share.png)
143
+
144
+ ```
145
+ plc = PlcAccess::Protocol::PlcShare::PlcShareProtocol.new host: '192.168.0.10', port: 10000, device_type: :fx
146
+ ```
147
+
148
+ You can choose a target PLC by using the device type option.
149
+
150
+ |device_type|Target PLCs|
151
+ |:-:|:--|
152
+ |:kv|Keyence PLCs|
153
+ |:fx|Mitsubishi Fx PLCs|
154
+ |:q|Mitsubishi Q/L/R PLCs|
155
+ |:omron|Omron PLCs|
156
+
157
+
83
158
  ## Contributing
84
159
 
85
160
  Bug reports and pull requests are welcome on GitHub at https://github.com/ito-soft-design/plc_access. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/ito-soft-design/plc_access/blob/master/CODE_OF_CONDUCT.md).
Binary file
Binary file
@@ -43,8 +43,17 @@ module ActAsType
43
43
  pack("f*").unpack("S*")
44
44
  end
45
45
 
46
- def to_string length=nil, encoding=Encoding::UTF_8
47
- s = pack("v*")
46
+ def to_string length=nil, encoding=Encoding::UTF_8, endian: :little
47
+ if length.respond_to?(:string_endian)
48
+ endian = length.string_endian
49
+ length = nil
50
+ end
51
+ if encoding.respond_to?(:string_endian)
52
+ endian = encoding.string_endian
53
+ encoding = Encoding::UTF_8
54
+ end
55
+ format = endian == :big ? "n*" : "v*"
56
+ s = pack(format)
48
57
  if length
49
58
  s = s[0, length].delete("\000")
50
59
  end
@@ -55,10 +64,19 @@ module ActAsType
55
64
 
56
65
  refine String do
57
66
 
58
- def as_ushort length=nil, encoding=Encoding::UTF_8
59
- a = self.encode(encoding).unpack("v*")
67
+ def as_ushort length=nil, encoding=Encoding::UTF_8, endian: :little
68
+ if length.respond_to?(:string_endian)
69
+ endian = length.string_endian
70
+ length = nil
71
+ end
72
+ if encoding.respond_to?(:string_endian)
73
+ endian = encoding.string_endian
74
+ encoding = Encoding::UTF_8
75
+ end
76
+ format = endian == :big ? "n*" : "v*"
77
+ a = self.encode(encoding).unpack(format)
60
78
  return a unless length
61
-
79
+
62
80
  s = (length + 1) / 2
63
81
  a += [0] * [s - a.length, 0].max
64
82
  a[0, s]
@@ -170,6 +170,10 @@ module PlcAccess
170
170
  raise "ERROR: return #{res} for set_bits_to_device(#{words}, #{device.name})" unless res == ack_packet
171
171
  end
172
172
 
173
+ def string_endian
174
+ :little
175
+ end
176
+
173
177
  def device_by_name(name)
174
178
  case name
175
179
  when String
@@ -160,6 +160,10 @@ module PlcAccess
160
160
  end
161
161
  end
162
162
 
163
+ def string_endian
164
+ :little
165
+ end
166
+
163
167
  def device_by_name(name)
164
168
  case name
165
169
  when String
@@ -107,6 +107,10 @@ module PlcAccess
107
107
  def -(other)
108
108
  self.class.new suffix, [number - other, 0].max
109
109
  end
110
+
111
+ def string_endian
112
+ :little
113
+ end
110
114
  end
111
115
  end
112
116
  end
@@ -147,6 +147,10 @@ module PlcAccess
147
147
  alias word value
148
148
  alias word= value=
149
149
 
150
+ def string_endian
151
+ :big
152
+ end
153
+
150
154
  def text(len = 8)
151
155
  n = (len + 1) / 2
152
156
  d = self
@@ -155,14 +159,16 @@ module PlcAccess
155
159
  a << d.value
156
160
  d = d.next_device
157
161
  end
158
- s = a.pack('n*').split("\x00").first
162
+ format = string_endian == :big ? 'n*' : 'v*'
163
+ s = a.pack(format).split("\x00").first
159
164
  s ? s[0, len] : ''
160
165
  end
161
166
 
162
167
  def set_text(value, len = 8)
163
168
  value = value[0, len]
164
169
  value << "\00" unless value.length.even?
165
- a = value.unpack('n*')
170
+ format = string_endian == :big ? 'n*' : 'v*'
171
+ a = value.unpack(format)
166
172
  d = self
167
173
  a.each do |v|
168
174
  d.value = v
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2025 ITO SOFT DESIGN Inc.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ dir = __dir__
27
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include? dir
28
+
29
+ require 'socket'
30
+ require 'logger'
31
+ require 'timeout'
32
+ require 'plc_share_protocol'
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2025 ITO SOFT DESIGN Inc.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ module PlcAccess
27
+ module Protocol
28
+ module PlcShare
29
+ class PlcShareProtocol < PlcAccess::Protocol::Keyence::KvProtocol
30
+ attr_accessor :device_type
31
+
32
+ def initialize(options = {})
33
+ super
34
+ @socket = nil
35
+ @host = options[:host] || '192.168.0.10'
36
+ @port = options[:port] || 10000
37
+ self.device_type = options[:device_type] if options[:device_type]
38
+ end
39
+
40
+ # Device type
41
+ # :kv Keyence device
42
+ # :fx Mitsubishi Fx device
43
+ # :q Mitsubishi Q/L device
44
+ # :omron Omron device
45
+ def device_type= type
46
+ @device_type = type
47
+ end
48
+
49
+ def string_endian
50
+ case @device_type
51
+ when :fx, :q
52
+ :little
53
+ else
54
+ :big
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def device_class
61
+ case @device_type
62
+ when :kv
63
+ PlcAccess::Protocol::Keyence::KvDevice
64
+ when :fx
65
+ PlcAccess::Protocol::Mitsubishi::FxDevice
66
+ when :q
67
+ PlcAccess::Protocol::Mitsubishi::QDevice
68
+ when :omron
69
+ PlcAccess::Protocol::Omron::OmronDevice
70
+ else
71
+ PlcAccess::Protocol::Keyence::KvDevice
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -58,6 +58,10 @@ module PlcAccess
58
58
 
59
59
  TIMEOUT = 1.0
60
60
 
61
+ def string_endian
62
+ :big
63
+ end
64
+
61
65
  # abstract methods
62
66
 
63
67
  def open; end
@@ -169,7 +173,7 @@ module PlcAccess
169
173
  v = [v] unless v.is_a? Array
170
174
  case args[0]
171
175
  when String
172
- self[args[0], 1] = v
176
+ self[args[0], v.size] = v
173
177
  when Range
174
178
  self[args[0].first, args[0].count] = v
175
179
  else
@@ -181,7 +185,8 @@ module PlcAccess
181
185
  c = args[1]
182
186
  values = args[2]
183
187
  values = [values] unless values.is_a? Array
184
- raise ArgumentError, "Count #{c} is not match #{args[2].size}." unless c == values.size
188
+ values += [0] * (c - values.size) if values.size < c
189
+ values = values[0, c] if values.size > c
185
190
 
186
191
  a = []
187
192
  if d.bit_device?
@@ -217,3 +222,4 @@ require 'plc_device'
217
222
  require 'keyence/keyence'
218
223
  require 'mitsubishi/mitsubishi'
219
224
  require 'omron/omron'
225
+ require 'plc_share/plc_share'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlcAccess
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plc_access
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katsuyoshi Ito
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-12-12 00:00:00.000000000 Z
10
+ date: 2026-02-14 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: serialport
@@ -49,6 +48,8 @@ files:
49
48
  - Rakefile
50
49
  - bin/console
51
50
  - bin/setup
51
+ - images/fx_comm_setting.png
52
+ - images/plc_share.png
52
53
  - lib/plc_access.rb
53
54
  - lib/plc_access/act_as_type.rb
54
55
  - lib/plc_access/protocol/keyence/keyence.rb
@@ -64,6 +65,8 @@ files:
64
65
  - lib/plc_access/protocol/omron/omron.rb
65
66
  - lib/plc_access/protocol/omron/omron_device.rb
66
67
  - lib/plc_access/protocol/plc_device.rb
68
+ - lib/plc_access/protocol/plc_share/plc_share.rb
69
+ - lib/plc_access/protocol/plc_share/plc_share_protocol.rb
67
70
  - lib/plc_access/protocol/protocol.rb
68
71
  - lib/plc_access/version.rb
69
72
  - plc_access.gemspec
@@ -74,7 +77,6 @@ metadata:
74
77
  homepage_uri: https://github.com/ito-soft-design/plc_access
75
78
  source_code_uri: https://github.com/ito-soft-design/plc_access
76
79
  changelog_uri: https://github.com/ito-soft-design/plc_access/CHANGES.md
77
- post_install_message:
78
80
  rdoc_options: []
79
81
  require_paths:
80
82
  - lib
@@ -89,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
91
  - !ruby/object:Gem::Version
90
92
  version: '0'
91
93
  requirements: []
92
- rubygems_version: 3.4.22
93
- signing_key:
94
+ rubygems_version: 3.6.5
94
95
  specification_version: 4
95
96
  summary: The PlcAccess communicates with PLCs.
96
97
  test_files: []