Skip to content

Commit bf10467

Browse files
committed
temp.
1 parent 2aaa0ee commit bf10467

File tree

2 files changed

+168
-97
lines changed

2 files changed

+168
-97
lines changed

pymodbus/datastore/simulator.py

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Pymodbus ModbusSimulatorContext."""
22
import dataclasses
33
import logging
4+
import random
45
import struct
56
import sys
7+
from datetime import datetime
68
from typing import Callable, Dict
79

810

@@ -122,39 +124,45 @@ def __init__(self):
122124
},
123125
}
124126

125-
def handle_type_bits(self, registers, start, stop, value, action):
127+
def handle_type_bits(self, registers, reg_count, start, stop, value, action):
126128
"""Handle type bits.
127129
128130
:meta private:
129131
"""
130132
for i in range(start, stop):
133+
if i >= reg_count:
134+
raise RuntimeError(f"Error section \"{Label.type_bits}\" addr {start}, {stop} out of range")
131135
if registers[i].type != CELL_TYPE_NONE:
132136
txt = f'ERROR Configuration invalid in section "{Label.type_bits}" register {i} already defined'
133137
raise RuntimeError(txt)
134138
registers[i].value = value
135139
registers[i].type = CELL_TYPE_BIT
136140
registers[i].action = action
137141

138-
def handle_type_uint16(self, registers, start, stop, value, action):
142+
def handle_type_uint16(self, registers, reg_count, start, stop, value, action):
139143
"""Handle type uint16.
140144
141145
:meta private:
142146
"""
143147
for i in range(start, stop):
148+
if i >= reg_count:
149+
raise RuntimeError(f"Error section \"{Label.type_uint16}\" addr {start}, {stop} out of range")
144150
if registers[i].type != CELL_TYPE_NONE:
145151
txt = f'ERROR Configuration invalid in section "{Label.type_uint16}" register {i} already defined'
146152
raise RuntimeError(txt)
147153
registers[i].value = value
148154
registers[i].type = CELL_TYPE_UINT16
149155
registers[i].action = action
150156

151-
def handle_type_uint32(self, registers, start, stop, value, action):
157+
def handle_type_uint32(self, registers, reg_count, start, stop, value, action):
152158
"""Handle type uint32.
153159
154160
:meta private:
155161
"""
156162
regs = ModbusSimulatorContext.build_registers_from_value(value, True)
157163
for i in range(start, stop, 2):
164+
if i+1 >= reg_count:
165+
raise RuntimeError(f"Error section \"{Label.type_uint32}\" addr {start}, {stop} out of range")
158166
if registers[i].type != CELL_TYPE_NONE:
159167
txt = f'ERROR Configuration invalid in section "{Label.type_uint32}" register {i} already defined'
160168
raise RuntimeError(txt)
@@ -168,13 +176,15 @@ def handle_type_uint32(self, registers, start, stop, value, action):
168176
registers[j].value = regs[1]
169177
registers[j].type = CELL_TYPE_NEXT
170178

171-
def handle_type_float32(self, registers, start, stop, value, action):
179+
def handle_type_float32(self, registers, reg_count, start, stop, value, action):
172180
"""Handle type uint32.
173181
174182
:meta private:
175183
"""
176184
regs = ModbusSimulatorContext.build_registers_from_value(value, False)
177185
for i in range(start, stop, 2):
186+
if i+1 >= reg_count:
187+
raise RuntimeError(f"Error section \"{Label.type_float32}\" addr {start}, {stop} out of range")
178188
if registers[i].type != CELL_TYPE_NONE:
179189
txt = f'ERROR Configuration invalid in section "{Label.type_float32}" register {i} already defined'
180190
raise RuntimeError(txt)
@@ -188,7 +198,7 @@ def handle_type_float32(self, registers, start, stop, value, action):
188198
registers[j].value = regs[1]
189199
registers[j].type = CELL_TYPE_NEXT
190200

191-
def handle_type_string(self, registers, start, stop, value, action):
201+
def handle_type_string(self, registers, reg_count, start, stop, value, action):
192202
"""Handle type string.
193203
194204
:meta private:
@@ -201,6 +211,8 @@ def handle_type_string(self, registers, start, stop, value, action):
201211
value = value.ljust(reg_len)
202212
for i in range(stop - start):
203213
inx = start + i
214+
if i+1 >= reg_count:
215+
raise RuntimeError(f"Error section \"{Label.type_start}\" addr {start}, {stop} out of range")
204216
if registers[inx].type != CELL_TYPE_NONE:
205217
txt = f'ERROR Configuration invalid in section "{Label.type_string}" register {inx} already defined'
206218
raise RuntimeError(txt)
@@ -261,26 +273,30 @@ def handle_setup_section(self, config, actions):
261273
entry[Label.action] = action
262274
return registers, offset, type_exception
263275

264-
def handle_invalid_address(self, registers, config):
276+
def handle_invalid_address(self, registers, reg_count, config):
265277
"""Handle invalid address"""
266278
for entry in Label.try_get(Label.invalid, config):
267279
if isinstance(entry, int):
268280
entry = [entry, entry]
269281
for i in range(entry[0], entry[1] + 1):
282+
if i >= reg_count:
283+
raise RuntimeError(f"Error section \"{Label.invalid}\" addr {entry} out of range")
270284
if registers[i].type != CELL_TYPE_NONE:
271285
txt = f'ERROR Configuration invalid in section "invalid" register {i} already defined'
272286
raise RuntimeError(txt)
273287
registers[i].type = CELL_TYPE_ILLEGAL
274288

275-
def handle_write_allowed(self, registers, config):
289+
def handle_write_allowed(self, registers, reg_count, config):
276290
"""Handle write allowed"""
277291
for entry in Label.try_get(Label.write, config):
278292
if isinstance(entry, int):
279293
entry = [entry, entry]
280294
for i in range(entry[0], entry[1] + 1):
295+
if i >= reg_count:
296+
raise RuntimeError(f"Error section \"{Label.write}\" addr {entry} out of range")
281297
registers[i].access = True
282298

283-
def handle_types(self, registers, actions, config):
299+
def handle_types(self, registers, actions, reg_count, config):
284300
"""Handle the different types"""
285301
for section, type_entry in self.config_types.items():
286302
layout = Label.try_get(section, config)
@@ -291,13 +307,14 @@ def handle_types(self, registers, actions, config):
291307
entry[Label.addr] = [entry[Label.addr], entry[Label.addr]]
292308
type_entry[Label.method](
293309
registers,
310+
reg_count,
294311
entry[Label.addr][0],
295312
entry[Label.addr][1] + 1,
296313
entry.get(Label.value, type_entry[Label.value]),
297314
actions[entry.get("action", type_entry[Label.action])],
298315
)
299316

300-
def handle_repeat(self, registers, config):
317+
def handle_repeat(self, registers, reg_count, config):
301318
"""Handle repeat.
302319
303320
:meta private:
@@ -310,6 +327,8 @@ def handle_repeat(self, registers, config):
310327
addr_to = Label.try_get(Label.repeat_to, entry)
311328
for inx in range(addr_to[0], addr_to[1] + 1):
312329
copy_inx = copy_start if copy_inx >= copy_end else copy_inx + 1
330+
if inx >= reg_count:
331+
raise RuntimeError(f"Error section \"{Label.repeat}\" entry {entry} out of range")
313332
registers[inx] = dataclasses.replace(registers[copy_inx])
314333

315334
def setup(self, config, actions, custom_actions) -> None:
@@ -323,11 +342,11 @@ def setup(self, config, actions, custom_actions) -> None:
323342
actions.update(custom_actions)
324343

325344
registers, offset, typ_exc = self.handle_setup_section(config, actions)
326-
self.handle_invalid_address(registers, config)
327-
self.handle_write_allowed(registers, config)
328-
self.handle_types(registers, actions, config)
329-
self.handle_repeat(registers, config)
330345
reg_count = len(registers)
346+
self.handle_invalid_address(registers, reg_count, config)
347+
self.handle_write_allowed(registers, reg_count, config)
348+
self.handle_types(registers, actions, reg_count, config)
349+
self.handle_repeat(registers, reg_count, config)
331350
for i in range(reg_count):
332351
if registers[i].type == CELL_TYPE_NONE:
333352
registers[i].type = CELL_TYPE_ILLEGAL
@@ -484,7 +503,7 @@ def getValues(self, func_code, address, count=1): # pylint: disable=invalid-nam
484503
for i in range(real_address, real_address + count):
485504
reg = self.registers[i]
486505
if reg.action:
487-
reg.action(i)
506+
reg.action(i, reg)
488507
result.append(reg.value)
489508
else:
490509
# bit access
@@ -494,7 +513,7 @@ def getValues(self, func_code, address, count=1): # pylint: disable=invalid-nam
494513
for i in range(real_address, real_address + reg_count):
495514
reg = self.registers[i]
496515
if reg.action:
497-
reg.action(i)
516+
reg.action(i, reg)
498517
while count and bit_index < 16:
499518
result.append(bool(reg.value & (2**bit_index)))
500519
count -= 1
@@ -533,21 +552,66 @@ def setValues(self, func_code, address, values): # pylint: disable=invalid-name
533552
# Internal action methods
534553
# --------------------------------------------
535554

536-
@classmethod
537-
def action_random(cls, inx):
538-
"""Update with random value."""
555+
def action_random(self, inx, cell):
556+
"""Update with random value.
539557
540-
@classmethod
541-
def action_increment(cls, inx):
542-
"""Increment value reset with overflow."""
558+
:meta private:
559+
"""
560+
if cell.type == CELL_TYPE_BIT:
561+
self.registers[inx].value = random.randint(0, 65536)
562+
elif cell.type == CELL_TYPE_FLOAT32:
563+
regs = self.build_registers_from_value(random.uniform(0.0, 100.0), False)
564+
self.registers[inx].value = regs[0]
565+
self.registers[inx+1].value = regs[1]
566+
elif cell.type == CELL_TYPE_UINT16:
567+
self.registers[inx].value = random.randint(0, 65536)
568+
elif cell.type == CELL_TYPE_UINT32:
569+
regs = self.build_registers_from_value(random.uniform(0.0, 100.0), True)
570+
self.registers[inx].value = regs[0]
571+
self.registers[inx+1].value = regs[1]
572+
573+
def action_increment(self, inx, cell):
574+
"""Increment value reset with overflow.
543575
544-
@classmethod
545-
def action_timestamp(cls, inx):
546-
"""Set current time."""
576+
:meta private:
577+
"""
578+
if cell.type == CELL_TYPE_BIT:
579+
self.registers[inx].value += 1
580+
elif cell.type == CELL_TYPE_FLOAT32:
581+
value = self.build_value_from_registers(self.registers[inx : inx+2])
582+
value += 1.0
583+
regs = self.build_registers_from_value(value, False)
584+
self.registers[inx].value = regs[0]
585+
self.registers[inx+1].value = regs[1]
586+
elif cell.type == CELL_TYPE_UINT16:
587+
self.registers[inx].value += 1
588+
elif cell.type == CELL_TYPE_UINT32:
589+
value = self.build_value_from_registers(self.registers[inx : inx+2])
590+
value += 1
591+
regs = self.build_registers_from_value(value, True)
592+
self.registers[inx].value = regs[0]
593+
self.registers[inx+1].value = regs[1]
594+
595+
def action_timestamp(self, inx, _cell):
596+
"""Set current time.
547597
548-
@classmethod
549-
def action_reset(cls, inx):
550-
"""Reboot server."""
598+
:meta private:
599+
"""
600+
x = datetime.now()
601+
self.registers[inx].value = x.tm_year - 1900
602+
self.registers[inx+1].value = x.tm_mon
603+
self.registers[inx+2].value = x.tm_mday
604+
self.registers[inx+3].value = x.tm_wday
605+
self.registers[inx+4].value = x.tm_hour
606+
self.registers[inx+5].value = x.tm_min
607+
self.registers[inx+1].value = x.tm_sec
608+
609+
def action_reset(self, _inx, _cell):
610+
"""Reboot server.
611+
612+
:meta private:
613+
"""
614+
raise RuntimeError("RESET server")
551615

552616
# --------------------------------------------
553617
# Internal helper methods

0 commit comments

Comments
 (0)