Created
October 3, 2015 00:30
-
-
Save kyoma-takahashi/e41eacd927987bed1b3e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/ruby | |
| SERIAL_DEVICE = '/dev/tty.usbserial-FTXYGCM5' | |
| # On Windows, like SERIAL_DEVICE = 'COM4' | |
| require 'rubygems' | |
| require 'rmodbus' | |
| # does not support 23 (0x17) Read/Write Multiple registers | |
| # according to https://github.com/flipback/rmodbus | |
| require 'serialport' | |
| # To prepare, | |
| # $ gem environment | |
| # $ gem install -V rmodbus serialport | |
| # To clean-up, | |
| # $ gem uninstall gserver rmodbus serialport | |
| # Serial constants according to the master configuration | |
| BAUD_RATE = 19_200 | |
| SERVER_ADDRESS = 50 | |
| SERIAL_OPTS = { | |
| :data_bit => 8, | |
| :stop_bits => 1, | |
| :parity => SerialPort::EVEN} | |
| # FYI, default :read_timeout is 100 in SerialPort lib | |
| # Modbus constants | |
| HOLDING_REGISTER_OFFSET = 40001 | |
| IDX_WATCHDOG_COUNTER_M2S = 40501 - HOLDING_REGISTER_OFFSET | |
| IDX_WATCHDOG_COUNTER_S2M = 40001 - HOLDING_REGISTER_OFFSET | |
| WATCHDOG_COUNTER_MAX = 2 ** 8 | |
| IDX_DATA = 40510 - HOLDING_REGISTER_OFFSET | |
| DATA_COUNTS = 28 | |
| INVALID_LENGTH_M2S = 0 | |
| # Constants for this implementation | |
| DUMMY_BYTE = 0x00 | |
| class DummySlave < ModBus::RTUServer | |
| def initialize(*arvg) | |
| super | |
| @holding_registers = Array.new(1 + IDX_DATA + DATA_COUNTS * 2 + INVALID_LENGTH_M2S) | |
| @holding_registers[0..IDX_DATA] = [DUMMY_BYTE] * IDX_DATA | |
| # On 2015-09-11, the entire array was filled by DUMMY_BYTE and | |
| # it was why we could not find the error of the master, | |
| # which sends wrong 0x10 messages 2 bytes shorter than requite. | |
| # On 2015-09-15, changed not to fill the part of data from the master. | |
| @slave_watchdog_counter = 0 | |
| holding_registers[IDX_WATCHDOG_COUNTER_S2M] = @slave_watchdog_counter | |
| @master_watchdog_counter = nil | |
| end | |
| def when_write | |
| timestamp = Time.now.utc.to_s | |
| if holding_registers[IDX_WATCHDOG_COUNTER_M2S] == @master_watchdog_counter | |
| warn "#{timestamp} Received a request to write holding registers with the same watchdog counter: #{@master_watchdog_counter}" | |
| else | |
| @master_watchdog_counter = holding_registers[IDX_WATCHDOG_COUNTER_M2S] | |
| @slave_watchdog_counter = (@slave_watchdog_counter + 1) % WATCHDOG_COUNTER_MAX | |
| holding_registers[IDX_WATCHDOG_COUNTER_S2M] = @slave_watchdog_counter | |
| $stderr.puts [timestamp, | |
| # holding_registers[0, IDX_DATA], | |
| holding_registers[IDX_WATCHDOG_COUNTER_S2M], | |
| holding_registers[IDX_WATCHDOG_COUNTER_M2S], | |
| holding_registers[IDX_DATA, DATA_COUNTS * 2]. | |
| each_slice(2).collect {|pair| | |
| if pair.include? nil | |
| '[' + pair.join(',') + ']' | |
| else | |
| sprintf('%.8e', pair.reverse.to_32f.first) | |
| end | |
| }#, | |
| # holding_registers[IDX_DATA + DATA_COUNTS * 2, holding_registers.length] | |
| ].flatten.join(',') | |
| # Array#to_32f is defined in rmodbus/ext.rb | |
| # The decimal digits of 32 bit float is 7.22 | |
| # according to https://en.wikipedia.org/wiki/IEEE_floating_point | |
| end | |
| end | |
| def parse_write_multiple_registers_func(req) | |
| ret_val = super | |
| # p ret_val | |
| # p quant = req[3,2].unpack('n')[0] | |
| # p addr = req[1,2].unpack('n')[0] | |
| # p @holding_registers.size | |
| when_write | |
| ret_val | |
| end | |
| end | |
| server = DummySlave.new(SERIAL_DEVICE, BAUD_RATE, SERVER_ADDRESS, SERIAL_OPTS) | |
| server.debug = true | |
| server.start | |
| server.join |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment