Class: Plc::Emulator::EmuPlc

Inherits:
Object
  • Object
show all
Includes:
PlcPlugins
Defined in:
lib/plc/emulator/emu_plc.rb

Direct Known Subclasses

Raspberrypi::RaspberrypiPlc

Constant Summary collapse

SUFFIXES =
%w(x y m c t l sc cc tc d cs ts h sd)
STOP_PLC_FLAG =

bit 1

2
CLEAR_PROGRAM_FLAG =

bit 2 require bit 1 on

4
CYCLE_RUN_FLAG =
2
INDEX_BIT_STACK_COUNT =
4
INDEX_BIT_STACK =
5
SIZE_OF_BIT_STACK =
3
SAVE_INTERVAL =

60.0

1.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ EmuPlc

Returns a new instance of EmuPlc.



60
61
62
63
64
65
66
67
68
69
# File 'lib/plc/emulator/emu_plc.rb', line 60

def initialize config={}
  SUFFIXES.each do |k|
    eval "@#{k}_devices = []"
  end
  @lock = Mutex.new
  @config = config
  @pending_save = nil
  reset
  load_plugins
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



39
40
41
# File 'lib/plc/emulator/emu_plc.rb', line 39

def config
  @config
end

#device_dictObject (readonly)

Returns the value of attribute device_dict.



40
41
42
# File 'lib/plc/emulator/emu_plc.rb', line 40

def device_dict
  @device_dict
end

#errorsObject (readonly)

Returns the value of attribute errors.



41
42
43
# File 'lib/plc/emulator/emu_plc.rb', line 41

def errors
  @errors
end

#program_dataObject

Returns the value of attribute program_data.



37
38
39
# File 'lib/plc/emulator/emu_plc.rb', line 37

def program_data
  @program_data
end

#program_pointerObject (readonly)

Returns the value of attribute program_pointer.



38
39
40
# File 'lib/plc/emulator/emu_plc.rb', line 38

def program_pointer
  @program_pointer
end

Instance Method Details

#boolObject



132
133
134
# File 'lib/plc/emulator/emu_plc.rb', line 132

def bool
  (stack_device.word & 1) != 0 ? true : false
end

#bool=(value) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/plc/emulator/emu_plc.rb', line 136

def bool= value
  if value
    stack_device.word |= 1
  else
    stack_device.word &= 0xfffe;
  end
end

#device_by_name(name) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/plc/emulator/emu_plc.rb', line 71

def device_by_name name
  @lock.synchronize {
    d = device_dict[name]
    unless d
      # try normalized name again
      new_d = EmuDevice.new(name)
      d = device_dict[new_d.name]
      unless d
        d = new_d
        d.plc = self
        device_dict[d.name] = d
      end
    end
    d
  }
end

#device_by_type_and_number(type, number) ⇒ Object



88
89
90
91
# File 'lib/plc/emulator/emu_plc.rb', line 88

def device_by_type_and_number type, number
  d = EmuDevice.new type, number
  device_by_name d.name
end

#execute_console_commands(line) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/plc/emulator/emu_plc.rb', line 152

def execute_console_commands line
  a = line.chomp.split(/\s+/)

  # separate data type except eval command.
  unless a[0] == "E"
    word = /([A-Z0-9]+)(\.H)?/ =~ a[1]
    a[1] = $1
  end

  case a[0]
  when /^ST/i
    d = device_by_name a[1]
    d.set_value true, :in
    "OK\r\n"
  when /^RS/i
    d = device_by_name a[1]
    d.set_value false, :in
    "OK\r\n"
  when /^RDS/i
    d = device_by_name a[1]
    c = a[2].to_i
    r = []
    if !word && d.bit_device?
      c.times do
        r << (d.bool(:out) ? 1 : 0)
        d = device_by_name (d+1).name
      end
    else
      case d.suffix
      when "PRG"
        c.times do
          r << program_data[d.number * 2, 2].pack("C*").unpack("n").first
          d = device_by_name (d+1).name
        end
      else
        c.times do
          r << d.word(:out)
          d = device_by_name (d+1).name
        end
      end
    end
    r.map{|e| e.to_s(16)}.join(" ") + "\r\n"

  # LadderDrive communication is bases KV protocol.
  # LadderDrive console is use WRS command only. (Not use WR command)
  # WR command is for irBoard. (http://irboard.itosoft.com)
  # A word value is communicated with hex format only in this product. (hard coding)
  when /^WRS?/i
    d = device_by_name a[1]
    a.insert 2, "1" if /^WR$/i =~ a.first
    c = a[2].to_i
    case d.suffix
    when "PRG"
      a[3, c].each do |v|
        program_data[d.number * 2, 2] = [v.to_i(16)].pack("n").unpack("C*")
        d = device_by_name (d+1).name
      end
    else
      if !word && d.bit_device?
        a[3, c].each do |v|
          d.set_value v == "0" ? false : true, :in
          d = d + 1#device_by_name (d+1).name
        end
      else
        a[3, c].each do |v|
          v = v.to_i(16)
          d.set_word v, :in
          #d.set_value v, :in
          d = d + 1#device_by_name (d+1).name
        end
      end
    end
    "OK\r\n"
  when /E/
    eval(a[1..-1].join(" ")).inspect
  else
    raise "Unknown command #{a.first}"
  end
end

#keep_device?(device) ⇒ Boolean

— queries

Returns:

  • (Boolean)


233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/plc/emulator/emu_plc.rb', line 233

def keep_device? device
  @keep_ranges ||= begin
    if config[:keep]
      config[:keep].map do |a|
        [device_by_name(a.first), device_by_name(a.last)]
      end
    else
      []
    end
  end
  @keep_ranges.each do |a|
    f = a.first
    e = a.last
    next unless f.suffix == device.suffix
    return true if (f.number..e.number).include? device.number
  end
  false
end

#resetObject



93
94
95
96
97
98
99
100
101
102
# File 'lib/plc/emulator/emu_plc.rb', line 93

def reset
  @word = 0
  @program_data = []
  @device_dict ||= {}
  @lock.synchronize {
    @device_dict.values.each do |d|
      d.reset
    end
  }
end

#runObject



144
145
146
147
148
149
150
# File 'lib/plc/emulator/emu_plc.rb', line 144

def run
  Thread.new do
    loop do
      run_cycle
    end
  end
end

#run_cycleObject



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/plc/emulator/emu_plc.rb', line 104

def run_cycle
  status_to_plc = device_by_name "SD0"
  status_form_plc = device_by_name "SD1"
  sync_input
  case status_to_plc.value & (STOP_PLC_FLAG | CLEAR_PROGRAM_FLAG)
  when STOP_PLC_FLAG
    status_form_plc.value = 0
    sleep 0.1
  when STOP_PLC_FLAG | CLEAR_PROGRAM_FLAG
    reset
    load
    status_form_plc.value = CLEAR_PROGRAM_FLAG
    sleep 0.1
  when 0
    status_form_plc.value = CYCLE_RUN_FLAG
    @program_pointer = 0
    clear_stacks
    while fetch_and_execution; end
    sleep 0.0001
  else
    sleep 0.1
  end
  # Save must be executed berofe sync_output, because changed flag was clear after sync_output
  save
  sync_output
  exec_plugins
end