Merge remote-tracking branch 'sasha/master'

# Conflicts:
#	scenes/tilemap/Control.gd
This commit is contained in:
MaD_CaT
2025-03-25 08:40:34 +03:00
16 changed files with 905 additions and 325 deletions

View File

@@ -1,4 +1,3 @@
@tool
# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License
# See `LICENSE.md` included in the source distribution for details.

View File

@@ -0,0 +1,205 @@
extends Node
## Constants For Modbus Server/Client
## This is the single location for storing default
## values for the servers and clients.
## A collection of modbus default values[br]
class Defaults:
## [param Port]
## The default modbus tcp server port (502)[br]
##
## [param TLSPort]
## The default modbus tcp over tls server port (802)[br]
##
## [param Backoff]
## The default exponential backoff delay (0.3 seconds)[br]
##
## [param Retries]
## The default number of times a client should retry the given
## request before failing (3)[br]
##
## [param RetryOnEmpty]
## A flag indicating if a transaction should be retried in the
## case that an empty response is received. This is useful for
## slow clients that may need more time to process a request.[br]
##
## [param RetryOnInvalid]
## A flag indicating if a transaction should be retried in the
## case that an invalid response is received.[br]
##
## [param Timeout]
## The default amount of time a client should wait for a request
## to be processed (3 seconds)[br]
##
## [param Reconnects]
## The default number of times a client should attempt to reconnect
## before deciding the server is down (0)[br]
##
## [param TransactionId]
## The starting transaction identifier number (0)[br]
##
## [param ProtocolId]
## The modbus protocol id. Currently this is set to 0 in all
## but proprietary implementations.[br]
##
## [param UnitId]
## The modbus slave addrss. Currently this is set to 0x00 which
## means this request should be broadcast to all the slave devices
## (really means that all the devices should respons).[br]
##
## [param Baudrate]
## The speed at which the data is transmitted over the serial line.
## This defaults to 19200.[br]
##
## [param Parity]
## The type of checksum to use to verify data integrity. This can be
## on of the following:[br]
## - (E)ven - 1 0 1 0 | P(0)[br]
## - (O)dd - 1 0 1 0 | P(1)[br]
## - (N)one - 1 0 1 0 | no parity[br]
## This defaults to (N)one.[br]
##
## [param Bytesize]
## The number of bits in a byte of serial data. This can be one of
## 5, 6, 7, or 8. This defaults to 8.[br]
##
## [param Stopbits]
## The number of bits sent after each character in a message to
## indicate the end of the byte. This defaults to 1.[br]
##
## [param ZeroMode]
## Indicates if the slave datastore should use indexing at 0 or 1.
## More about this can be read in section 4.4 of the modbus specification.[br]
##
## [param IgnoreMissingSlaves]
## In case a request is made to a missing slave, this defines if an error
## should be returned or simply ignored. This is useful for the case of a
## serial server emulater where a request to a non-existant slave on a bus
## will never respond. The client in this case will simply timeout.[br]
##
## [param broadcast_enable]
## When False unit_id 0 will be treated as any other unit_id. When True and
## the unit_id is 0 the server will execute all requests on all server
## contexts and not respond and the client will skip trying to receive a
## response. Default value False does not conform to Modbus spec but maintains
## legacy behavior for existing pymodbus users[br]
const Port: = 502
const TLSPort: = 802
const Backoff: = 0.3
const Retries: = 3
const RetryOnEmpty: = false
const RetryOnInvalid: = false
const Timeout: = 3
const Reconnects: = 0
const TransactionId: = 0
const ProtocolId: = 0
const UnitId: = 0x00
const Baudrate: = 19200
const Parity: = 'N'
const Bytesize: = 8
const Stopbits: = 1
const ZeroMode: = false
const IgnoreMissingSlaves: = false
const ReadSize: = 1024
const broadcast_enable: = false
## These represent various status codes in the modbus
## protocol.[br]
class ModbusStatus extends Object:
##
## [param Waiting]
## This indicates that a modbus device is currently
## waiting for a given request to finish some running task.[br]
##
## [param Ready]
## This indicates that a modbus device is currently
## free to perform the next request task.[br]
##
## [param On]
## This indicates that the given modbus entity is on[br]
##
## [param Off]
## This indicates that the given modbus entity is off[br]
##
## [param SlaveOn]
## This indicates that the given modbus slave is running[br]
##
## [param SlaveOff]
## This indicates that the given modbus slave is not running[br]
const Waiting: = 0xffff
const Ready: = 0x0000
const On: = 0xff00
const Off: = 0x0000
const SlaveOn: = 0xff
const SlaveOff: = 0x00
class Endian:
## An enumeration representing the various byte endianess.
## [param Auto]
## This indicates that the byte order is chosen by the
## current native environment.[br]
## [param Big]
## This indicates that the bytes are in little endian format.[br]
## [param Little]
## This indicates that the bytes are in big endian format
## [i]I am simply borrowing the format strings from the
## python struct module for my convenience.[/i]
const Auto: = '@'
const Big: = '>'
const Little: = '<'
class ModbusPlusOperation:
## Represents the type of modbus plus request
## [param GetStatistics]
## Operation requesting that the current modbus plus statistics
## be returned in the response.[br]
## [param ClearStatistics]
## Operation requesting that the current modbus plus statistics
## be cleared and not returned in the response.[br]
const GetStatistics: = 0x0003
const ClearStatistics: = 0x0004
class DeviceInformation:
## Represents what type of device information to read
##
## [param Basic]
## This is the basic (required) device information to be returned.
## This includes VendorName, ProductCode, and MajorMinorRevision
## code.[br]
##
## [param Regular]
## In addition to basic data objects, the device provides additional
## and optional identification and description data objects. All of
## the objects of this category are defined in the standard but their
## implementation is optional.[br]
##
## [param Extended
## In addition to regular data objects, the device provides additional
## and optional identification and description private data about the
## physical device itself. All of these data are device dependent.[br]
##
## [param Specific]
## Request to return a single data object.[br]
const Basic: = 0x01
const Regular: = 0x02
const Extended: = 0x03
const Specific: = 0x04
class MoreData:
## Represents the more follows condition
## [param Nothing]
## This indiates that no more objects are going to be returned.[br]
##
## [param KeepReading]
## This indicates that there are more objects to be returned.[br]
const Nothing: = 0x00
const KeepReading: = 0xFF

View File

@@ -0,0 +1,87 @@
extends Node
## Pymodbus Exceptions. Custom exceptions to be used in the Modbus code.
## Base modbus exception
class ModbusException:
var string: String = ''
## Initialize the exception.
## [param s] The message to append to the error
func _init(s: String): string = s
func _to_string(): return '<ModbusException>: %s' % string
func isError(): return true
func raise(): push_error(string)
### Error resulting from data i/o
class ModbusIOException extends ModbusException:
var fcode
var message
## Initialize the exception
## [param s] The message to append to the error
func _init(s: String = '', function_code=null):
fcode = function_code
message = '[Input/Output] %s' % s
ModbusException.new(message).raise()
## Error resulting from invalid parameter
class ParameterException extends ModbusException:
## Initialize the exception
## [param s] The message to append to the error
func _init(s: String = ''):
var message = '[Invalid Parameter] %s' % s
ModbusException.new(message).raise()
## Error resulting from making a request to a slave
## that does not exist
class NoSuchSlaveException extends ModbusException:
## Initialize the exception.
## [param s] The message to append to the error
func _init(s: String = ''):
var message = '[No Such Slave] %s' % s
ModbusException.new(message).raise()
## Error resulting from not implemented function
class NotImplementedException extends ModbusException:
## Initialize the exception
## [param s]: The message to append to the error
func _init(s: String = ''):
var message = '[Not Implemented] %s' % s
ModbusException.new(message).raise()
## Error resulting from a bad connection
class ConnectionException extends ModbusException:
## Initialize the exception
## [param s] The message to append to the error
func _init(s: String = ''):
var message: String = '[Connection] %s' % s
ModbusException.new(message).raise()
## Error resulting from invalid response received or decoded
class InvalidMessageReceivedException extends ModbusException:
## Initialize the exception
## [param s] The message to append to the error
func _init(s: String = ''):
var message: String = '[Invalid Message] %s' % s
ModbusException.new(message).raise()
## Error resulting from failing to register a custom message request/response
class MessageRegisterException extends ModbusException:
func _init(s: String = ''):
var message: String = '[Error registering message] %s' % s
ModbusException.new(message).raise()
## Error resulting from modbus response timeout
class TimeOutException extends ModbusException:
## Initialize the exception
## [param s] The message to append to the error
func _init(s: String = ''):
var message: String = '[Timeout] %s' % s
ModbusException.new(message).raise()

187
modbus/pymodbus/pdu.gd Normal file
View File

@@ -0,0 +1,187 @@
extends Node
## Contains base classes for modbus request/response/error packets
# В автозагрузке должно быть
# from pymodbus.exceptions import
# from pymodbus.constants import Defaults
# from pymodbus.utilities import rtuFrameSize
# Base PDU's
class ModbusPDU extends Object:
## Base class for all Modbus messages
## [param transaction_id]
## This value is used to uniquely identify a request
## response pair. It can be implemented as a simple counter
## [param protocol_id]
## This is a constant set at 0 to indicate Modbus. It is
## put here for ease of expansion.
## [param unit_id]
## This is used to route the request to the correct child. In
## the TCP modbus, it is used for routing (or not used at all. However,
## for the serial versions, it is used to specify which child to perform
## the requests against. The value 0x00 represents the broadcast address
## (also 0xff).
## [param check]
## This is used for LRC/CRC in the serial modbus protocols
## [param skip_encode]
## This is used when the message payload has already been encoded.
## Generally this will occur when the PayloadBuilder is being used
## to create a complicated message. By setting this to True, the
## request will pass the currently encoded message through instead
## of encoding it again.
var transaction_id
var protocol_id
var unit_id
var skip_encode
var check
var function_code = 0
var exception_code = 0
## Initializes the base data for a modbus request
func _init(kwargs: Dictionary):
transaction_id = kwargs.get('transaction', constants.Defaults.TransactionId)
protocol_id = kwargs.get('protocol', constants.Defaults.ProtocolId)
unit_id = kwargs.get('unit', constants.Defaults.UnitId)
skip_encode = kwargs.get('skip_encode', false)
check = 0x0000
## Encodes the message
## [b]raises[/b] A not implemented exception
func encode():
exceptions.NotImplementedException.new().raise()
## Decodes data part of the message.
## [param data] is a string object
## [b]raises[/b] A not implemented exception
func decode(data: PackedByteArray):
exceptions.NotImplementedException.new().raise()
## Calculates the size of a PDU.
## [param buffer] A buffer containing the data that have been received.
## [b]returns[/b] The number of bytes in the PDU.
func calculateRtuFrameSize(buffer: PackedByteArray):
var rc = self.get('_rtu_frame_size')
if rc != null:
return rc
rc = self.get('_rtu_byte_count_pos')
if rc != null:
return utilities.rtuFrameSize(buffer, rc)
else:
exceptions.NotImplementedException.new('Cannot determine RTU frame size for %s' % self).raise()
## Base class for a modbus request PDU
class ModbusRequest extends ModbusPDU:
func _init(kwargs: Dictionary):
# Proxy to the lower level initializer
super(kwargs)
## Builds an error response based on the function[br]
## [param exception] The exception to return[br]
## [b]raises[/b] An exception response[br]
func doException(exception):
var exc = exceptions.ExceptionResponse(function_code, exception)
log.error(exc)
return exc
class ModbusResponse extends ModbusPDU:
## Base class for a modbus response PDU
## [param should_respond]
## A flag that indicates if this response returns a result back
## to the client issuing the request
## [param _rtu_frame_size]
## Indicates the size of the modbus rtu response used for
## calculating how much to read.
var should_respond = true
## Proxy to the lower level initializer
func _init(kwargs: Dictionary):
super(kwargs)
## Checks if the error is a success or failure
func isError():
return function_code > 0x80
## Exception PDU's. An enumeration of the valid modbus exceptions
class ModbusExceptions:
const IllegalFunction = 0x01
const IllegalAddress = 0x02
const IllegalValue = 0x03
const SlaveFailure = 0x04
const Acknowledge = 0x05
const SlaveBusy = 0x06
const MemoryParityError = 0x08
const GatewayPathUnavailable = 0x0A
const GatewayNoResponse = 0x0B
var _decoded: = {}
func _init():
for prop in get_property_list():
_decoded[get(prop.name)] = prop.name
## Given an error code, translate it to a string error name.[br]
## [param code] The code number to translate
func decode(code: int) -> String: return _decoded.get(code)
## Base class for a modbus exception PDU
class ExceptionResponse extends ModbusResponse:
var ExceptionOffset = 0x80
var _rtu_frame_size = 5
var original_code = function_code
## Initializes the modbus exception response
## [param function_code] The function to build an exception response for
## [param exception_code] The specific modbus exception to return
func _init(func_code, kwargs: Dictionary, except_code: int = 0):
super(kwargs)
function_code = func_code | ExceptionOffset
exception_code = except_code
original_code = function_code
## Encodes a modbus exception response
func encode(): return exception_code
## Decodes a modbus exception response[br]
## [param data] The packet data to decode
func decode(data: PackedByteArray):
exception_code = data.decode_u8(0)
## Builds a representation of an exception response[/br]
## [b]returns[/b] The string representation of an exception response
func _to_string() -> String:
var message = ModbusExceptions.new().decode(self.exception_code)
return 'Exception Response(%d, %d, %s)' % [function_code, original_code, message]
## Defines the Modbus slave exception type 'Illegal Function'
## This exception code is returned if the slave::
## - does not implement the function code **or**
## - is not in a state that allows it to process the function
class IllegalFunctionRequest extends ModbusRequest:
var ErrorCode = 1
## Initializes a IllegalFunctionRequest[br]
## [param function_code] The function we are erroring on[br]
func _init(func_code, kwargs):
super(kwargs)
self.function_code = func_code
## This is here so this failure will run correctly[br]
## [param data] Not used[br]
func decode(_data: PackedByteArray): pass
## Builds an illegal function request error response
## [param context] The current context for the message
## [b]returns[/b] The error response packet
func execute(context):
return ExceptionResponse.new(function_code, ErrorCode)

View File

@@ -0,0 +1,177 @@
extends Node
## Modbus Utilities.
## A collection of utilities for packing data, unpacking
## data computing checksums, and decode checksums.
## Modbus Client States
class ModbusTransactionState extends Object:
const IDLE: = 0
const SENDING: = 1
const WAITING_FOR_REPLY: = 2
const WAITING_TURNAROUND_DELAY: = 3
const PROCESSING_REPLY: = 4
const PROCESSING_ERROR: = 5
const TRANSACTION_COMPLETE: = 6
const RETRYING: = 7
const NO_RESPONSE_STATE: = 8
func state_to_string(state) -> String:
var states: = {
ModbusTransactionState.IDLE: 'IDLE',
ModbusTransactionState.SENDING: 'SENDING',
ModbusTransactionState.WAITING_FOR_REPLY: 'WAITING_FOR_REPLY',
ModbusTransactionState.WAITING_TURNAROUND_DELAY: 'WAITING_TURNAROUND_DELAY',
ModbusTransactionState.PROCESSING_REPLY: 'PROCESSING_REPLY',
ModbusTransactionState.PROCESSING_ERROR: 'PROCESSING_ERROR',
ModbusTransactionState.TRANSACTION_COMPLETE: 'TRANSACTION_COMPLETE',
ModbusTransactionState.RETRYING: 'RETRYING TRANSACTION' }
return states.get(state, null)
var __crc16_table: = []
func _ready():
__crc16_table = __generate_crc16_table()
## Creates a string out of an array of bits
## [code]
## var bits = [False, True, False, True]
## var result = pack_bitstring(bits)
## [/code]
func pack_bitstring(bits: Array):
var ret = PackedByteArray()
var i = 0
var packed: int = 0
for bit in bits:
if bit:
packed += 128
i += 1
if i == 8:
ret += packed
i = 0
packed = 0
else:
packed >>= 1
if 0 < i < 8:
packed >>= (7 - i)
ret += packed
return ret
## Creates bit array out of a string
## param string: The modbus data packet to decode
## [code]
## var bytes = 'bytes to decode'
## var result = unpack_bitstring(bytes)
## [/code]
func unpack_bitstring(string: String):
var psa: = string.to_ascii_buffer()
var byte_count = psa.size()
var bits: = []
for byte in byte_count:
var value = psa.decode_u8(byte)
for i in 8:
bits.append((value & (1 << i)) > 0)
return bits
## Returns byte string from a given string
## [param s]
func make_byte_string(s) -> PackedByteArray:
return PackedByteArray(s)
# Error Detection Functions
func __generate_crc16_table() -> Array:
## Generates a crc16 lookup table
## note:: This will only be generated once
var result: = []
for byte in 256:
var crc = 0x0000
for i in 8:
if (byte ^ crc) & 0x0001:
crc = (crc >> 1) ^ 0xa001
else:
crc >>= 1
byte >>= 1
result.append(crc)
return result
## Computes a crc16 on the passed in string. For modbus,
## this is only used on the binary serial protocols (in this
## case RTU). The difference between modbus's crc16 and a normal crc16
## is that modbus starts the crc value out at 0xffff.
## [param data] The data to create a crc16 of
## [b]returns[/b] The calculated CRC
func computeCRC(data: PackedByteArray) -> int:
var crc: int = 0xffff
for a in data:
var idx = __crc16_table[(crc ^ a) & 0xff]
crc = ((crc >> 8) & 0xff) ^ idx
return ((crc << 8) & 0xff00) | ((crc >> 8) & 0x00ff)
## Checks if the data matches the passed in CRC
## [param data] The data to create a crc16 of
## [param check] The CRC to validate
## [b]returns[/b] True if matched, False otherwise
func checkCRC(data, check: int) -> bool:
return computeCRC(data) == check
## Used to compute the longitudinal redundancy check
## against a string. This is only used on the serial ASCII
## modbus protocol. A full description of this implementation
## can be found in appendex B of the serial line modbus description.
## [param data] The data to apply a lrc to
## [b]return[/b] The calculated LRC
func computeLRC(data: PackedByteArray) -> int:
var lrc: int = 0
for a in data:
lrc += a
lrc &= 0xff
lrc = (lrc ^ 0xff) + 1
return lrc & 0xff
## Checks if the passed in data matches the LRC
## [param data] The data to calculate
## [param check] The LRC to validate
## [b]returns[/b] True if matched, False otherwise
func checkLRC(data: PackedByteArray, check: int) -> bool:
return computeLRC(data) == check
## Calculates the size of the frame based on the byte count.
## param data: The buffer containing the frame.
## param byte_count_pos: The index of the byte count in the buffer.
## returns: The size of the frame.
##
## The structure of frames with a byte count field is always the
## same:
##
## first, there are some header fields
## then the byte count field
## then as many data bytes as indicated by the byte count,
## finally the CRC (two bytes).
##
## To calculate the frame size, it is therefore sufficient to extract
## the contents of the byte count field, add the position of this
## field, and finally increment the sum by three (one byte for the
## byte count field, two for the CRC).
func rtuFrameSize(data: PackedByteArray, byte_count_pos: int) -> int:
return data.decode_u32(byte_count_pos) + byte_count_pos + 3
## Returns hex representation of bytestring received
## [param packet]
## [b]return[/b]
func hexlify_packets(packet: PackedByteArray):
if not packet: return ''
var s = String()
for ch in packet:
s += '%02x' % ch
return s

View File

@@ -0,0 +1,44 @@
extends Node
## Handle the version information here; you should only have to
## change the version tuple. Since we are using twisted's
## version class, we can also query the svn version as well using
## the local .entries file.
var version = Version.new('pymodbus', 2, 5, 3)
class Version extends Object:
var package
var major
var minor
var micro
var pre
var name
## [param package] Name of the package that this is a version of.[br]
## [param major] The major version number.[br]
## [param minor] The minor version number.[br]
## [param micro] The micro version number.[br]
## [param pre] The pre release tag.[br]
func _init(pkg, mjr, mnr, mcr, pr=null):
self.package = pkg
self.major = mjr
self.minor = mnr
self.micro = mcr
self.pre = pr
self.name = 'pymodbus'
## Return a string in canonical short version format
## <major>.<minor>.<micro>.<pre>
func short():
if self.pre:
return '%d.%d.%d.%s' % [self.major, self.minor, self.micro, self.pre]
else:
return '%d.%d.%d' % [self.major, self.minor, self.micro]
## Returns a string representation of the object
## A string representation of this object
func _to_string() -> String:
return '[%s, version %s]' % [self.package, self.short()]

View File

@@ -55,6 +55,11 @@ signal pressed(control: PanelContainer)
func _on_button_pressed():
emit_signal('pressed', self)
func _enter_tree() -> void:
if is_inside_tree():
$margin/vbox/title/lbl_using.self_modulate = Color.CADET_BLUE
"
[sub_resource type="GDScript" id="GDScript_45hqb"]
@@ -132,20 +137,20 @@ columns = 2
[node name="fname" type="Label" parent="margin/vbox/title"]
self_modulate = Color(1, 1, 1, 0.627451)
layout_mode = 2
size_flags_horizontal = 6
size_flags_horizontal = 2
theme_override_font_sizes/font_size = 17
horizontal_alignment = 1
vertical_alignment = 1
[node name="lbl_using" type="Label" parent="margin/vbox/title"]
self_modulate = Color(0.372549, 0.619608, 0.627451, 1)
layout_mode = 2
size_flags_horizontal = 3
size_flags_horizontal = 10
size_flags_vertical = 6
tooltip_text = "Частота питающего напряжения"
mouse_filter = 0
theme_override_font_sizes/font_size = 22
text = "<нет данных>"
horizontal_alignment = 1
horizontal_alignment = 2
vertical_alignment = 1
[node name="table" type="GridContainer" parent="margin/vbox"]

View File

@@ -8,120 +8,25 @@ extends 'res://scenes/контроль/элемент-я.gd'
## информационного взаимодействия изделия 5П-28
## с аппаратурой УА-РЭП на кораблях проекта 23900
@export var base_input_address: = 0 ## Базовый адрес регистров входов
@export var base_holding_address: = 0 ## Базовый адрес регистров хранения
@export var regs_input_count: = 5 ## Количество регистров входов
@export var regs_holding_count: = 4 ## Количество регистров хранения
@export var modbus_address: = 3 ## Адрес устройства на шине Modbus
@export var request_period: = 1.0 ## Период отправки команд на шину Modbus
@export var reconnect_period: = 5.0 ## Период переподключения
@export var base_input_address: = 0 ## Базовый адрес регистров входов
@export var base_holding_address: = 0 ## Базовый адрес регистров хранения
@export var regs_input_count: = 5 ## Количество регистров входов
@export var regs_holding_count: = 4 ## Количество регистров хранения
@export var modbus_address: = 7 ## Адрес устройства на шине Modbus
@export var request_period: = 200 ## Период в секундах отправки команд на шину Modbus
@export var reconnect_period: = 3000 ## Период переподключения в секундах
var regs_input: = {} ## Регистры входные
var regs_holding: = {} ## Регистры хранения
var write_stack: = [] ## Стек команд для записи
var holding_stack: = [] ## Стек команд для чтения регистров хранения
var input_stack: = [] ## Стек команд для чтения регистров входов
var read_step: = 0
var switches_sync: = false
var timer = Timer.new()
var timer_reconnect = Timer.new()
var regs_input: = {} ## Регистры входные
var regs_holding: = {} ## Регистры хранения
var switches_sync: = false ## Флаг. Если установлен, то можно переключать
class StackItem:
var addr: = 0
var data = null
func _init(a: int, d): addr = a; data = d
func _to_string() -> String: return '%s: %s' % [addr, data]
func on_data_received(_data: PackedByteArray): pass
## Обработчик таймера
func _on_timeout(unit_sch3) -> void:
if write_stack.size():
var ad = write_stack.pop_front()
if not unit_sch3.write(ad.addr, ad.data):
write_stack.push_back(ad)
if (read_step == 0) and (input_stack.size() == 0):
var ad = StackItem.new(base_input_address, regs_input_count)
input_stack.push_back(ad)
elif (read_step == 1) and (holding_stack.size() == 0):
var ad = StackItem.new(base_holding_address, regs_holding_count)
holding_stack.push_back(ad)
if input_stack.size():
var ad = input_stack.pop_front()
if not unit_sch3.read_input(ad.addr, ad.data):
input_stack.push_back(ad)
if holding_stack.size():
var ad = holding_stack.pop_front()
if not unit_sch3.read_holding(ad.addr, ad.data):
holding_stack.push_back(ad)
read_step += 1
read_step %= 2
func _on_timeout_recconect(unit_sch3):
var unit_key = settings.get_unit_key(unit_sch3.name)
var mbc = network.mbcs[unit_key]
mbc.try_reconnect()
var mb_data = {'code': 'read_holding', 'data': [0, 4], 'unit': 0}
mbc.send_to(mb_data)
## Вызывается при изменении состояния выключателя[br]
## [param val] - Состояние выключателя[br]
## [param meta] - Адреса регистров и индексы битов назначенных выключателю[br]
func on_toggled_switch(val: bool, meta: Array):
var on_addr = meta[0]
var on_bit = meta[1]
var off_addr = meta[2]
var off_bit = meta[3]
if regs_holding.has(on_addr) and regs_holding.has(off_addr):
regs_holding[on_addr] = tools.set_bit(regs_holding[on_addr], on_bit, val)
regs_holding[off_addr] = tools.set_bit(regs_holding[off_addr], off_bit, not val)
push_write_holding()
## Заносит в очередь команду чтения регистров хранения
func push_write_holding():
var regs_data: = []
var keys = regs_holding.keys()
keys.sort() # Ключи в словаре хранятся не упорядочено
for addr in keys:
regs_data.append(regs_holding[addr])
write_stack.push_back(StackItem.new(keys[0], regs_data))
func _ready() -> void:
if Engine.is_editor_hint(): return
var unit_key = settings.get_unit_key(unit_name)
var unit_sch3 = network.units[unit_key]
unit_sch3.mb_addr = modbus_address
var items = get_tree().get_nodes_in_group('bits_items_switch')
for item in items:
var meta = item.get_meta('bits')
item.connect('toggled', on_toggled_switch.bind(meta))
item.disabled = true
unit_sch3.connect('resp_input', on_resp_input)
unit_sch3.connect('resp_holding', on_resp_holding)
unit_sch3.connect('command_fail', on_command_fail)
timer.connect('timeout', _on_timeout.bind(unit_sch3))
add_child(timer)
timer.start(request_period)
timer_reconnect.connect('timeout', _on_timeout_recconect.bind(unit_sch3))
add_child(timer_reconnect)
func on_command_fail(unit_sch3):
unit_sch3.cmd_state = unit.Unit.CmdState.DONE
timer.stop()
timer_reconnect.start(reconnect_period)
func on_error(msg): push_error(msg)
## Вызывается, когда состояния прибора Щ3 "на связи" изменяется[br]
## [param unit_sch3] - Экземпляр представления прибора Щ3
func on_line_changed(unit_sch3: sch_3.Sch3):
func on_line_changed_sch3(unit_sch3):
for item in get_tree().get_nodes_in_group('bits_items_good'):
item.texture = textures[STATE_VAL.NONE]
if not unit_sch3.online:
@@ -129,22 +34,63 @@ func on_line_changed(unit_sch3: sch_3.Sch3):
item.disabled = true
regs_holding.clear()
regs_input.clear()
write_stack.clear()
input_stack.clear()
holding_stack.clear()
switches_sync = false
$margin/vbox/grid1/lbl_freq.text = '<нет данных>'
$margin/vbox/grid1/lbl_freq.self_modulate = Color.CADET_BLUE
$margin/vbox/grid1/state_freq.texture = textures[STATE_VAL.NONE]
$margin/vbox/grid/state.texture = textures[STATE_VAL.NONE]
else:
timer_reconnect.stop()
timer.start(request_period)
## Вызывается при изменении состояния выключателя[br]
## [param val] - Состояние выключателя[br]
## [param meta] - Адреса регистров и индексы битов назначенных выключателю[br]
func on_toggled_switch(val: bool, meta: Array, unit_sch3):
var on_addr = meta[0]
var on_bit = meta[1]
var off_addr = meta[2]
var off_bit = meta[3]
if regs_holding.has(on_addr) and regs_holding.has(off_addr):
regs_holding[on_addr] = tools.set_bit(regs_holding[on_addr], on_bit, val)
regs_holding[off_addr] = tools.set_bit(regs_holding[off_addr], off_bit, not val)
unit_sch3.push_write_holding(regs_holding)
func _enter_tree() -> void:
super._enter_tree()
if Engine.is_editor_hint(): return
var unit_key = settings.get_unit_key(unit_name)
var unit_sch3 = network.units[unit_key]
var items = get_tree().get_nodes_in_group('bits_items_switch')
for item in items:
var meta = item.get_meta('bits')
item.connect('toggled', on_toggled_switch.bind(meta, unit_sch3))
item.disabled = true
unit_sch3.base_holding_address = base_holding_address
unit_sch3.regs_holding_count = regs_holding_count
unit_sch3.base_input_address = base_input_address
unit_sch3.regs_input_count = regs_input_count
unit_sch3.request_period = request_period
unit_sch3.reconnect_period = reconnect_period
unit_sch3.connect('read', on_read.bind(unit_sch3))
unit_sch3.connect('read_input', on_input)
unit_sch3.connect('error', on_error)
unit_sch3.connect('line_changed', on_line_changed_sch3)
func _exit_tree() -> void:
if Engine.is_editor_hint(): return
var unit_key = settings.get_unit_key(unit_name)
var unit_sch3 = network.units[unit_key]
unit_sch3.disconnect('read', on_read.bind(unit_sch3))
unit_sch3.disconnect('read_input', on_input.bind(unit_sch3))
unit_sch3.disconnect('error', on_error)
unit_sch3.disconnect('line_changed', on_line_changed_sch3)
## Вызывается по сигналу "приняты данные чтения регистров хранения"[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Массив значений прочитанных из регистров.
func on_resp_holding(base_addr: int, data: Array):
func on_read(base_addr: int, data: Array, unit_sch3):
if (base_addr != base_holding_address) or (data.size() < regs_holding_count):
return
for i in data.size():
@@ -162,13 +108,13 @@ func on_resp_holding(base_addr: int, data: Array):
item.button_pressed = val0
item.disabled = false
regs_holding[byte1] = tools.set_bit(regs_holding[byte1], bit1, not val0)
push_write_holding()
unit_sch3.push_write_holding(regs_holding)
## Вызывается по сигналу "приняты данные чтения регистров входов".[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Массив значений прочитанных из регистров.[br]
func on_resp_input(base_addr: int, data: Array):
func on_input(base_addr: int, data: Array):
if !is_inside_tree():
return
if (base_addr != base_input_address) or (data.size() < regs_input_count):
@@ -182,6 +128,7 @@ func on_resp_input(base_addr: int, data: Array):
regs_input[base_addr + i] = data[i]
# Таблица 3.15, Регистр PowerState
$margin/vbox/grid1/lbl_freq.text = '%d' % (regs_input[4] & 0x1ff)
$margin/vbox/grid1/lbl_freq.self_modulate = Color.WHITE
$margin/vbox/grid1/state_freq.texture \
= textures[STATE_VAL.GOOD] if regs_input[4] & (1 << 15) \
else textures[STATE_VAL.ERROR]

View File

@@ -1,12 +0,0 @@
extends Control
var scene_list=[]
func node_list(node):
scene_list.append(node)
func _enter_tree():
get_tree().node_added.connect(self.node_list)
func _ready():
get_tree().node_added.disconnect(self.node_list) #should be first string in _ready()
print(scene_list)

View File

@@ -1,3 +0,0 @@
[gd_scene format=3 uid="uid://e3sw6q228iai"]
[node name="Navig" type="Node2D"]

View File

@@ -94,7 +94,7 @@ expand_mode = 1
[node name="fname" type="Label" parent="margin/vbox/grid"]
self_modulate = Color(1, 1, 1, 0.627451)
layout_mode = 2
size_flags_horizontal = 3
size_flags_horizontal = 2
size_flags_vertical = 6
theme_override_font_sizes/font_size = 17
horizontal_alignment = 1

View File

@@ -48,29 +48,6 @@ class SocketTCP extends TCPServer:
peer.put_data(data)
class Modbus extends ModbusClientRtu:
var unit_name
func send_to(data):
if data['code'] == 'write':
var addr = data['data'].pop_at(0)
request_write(addr, data['data'])
elif data['code'] == 'read_holding':
request_read(data['data'][0], data['data'][1])
elif data['code'] == 'read_input':
request_read_input(data['data'][0], data['data'][1])
func try_reconnect():
var port = settings.UnitProfiles[unit_name][1]
var params = settings.UnitProfiles[unit_name][2]
thread_stop()
close()
var rc = open(port, params[0], params[1], params[2], params[3], params[4])
if rc != Error.OK:
push_error('ошибка: \"%s\" - не открывается' % port)
set_indication_timeout(params[5])
thread_run()
var poll_sockets: Array[Socket]
var tcp_sockets: Array
var units: Dictionary
@@ -124,17 +101,9 @@ func create_serial(nm) -> Serial:
return sp
func create_modbus(nm, mbc_unit) -> Modbus:
var port = settings.UnitProfiles[nm][1]
var params = settings.UnitProfiles[nm][2]
var mbc: = Modbus.new()
mbc.connect('read', mbc_unit.on_read)
mbc.connect('read_input', mbc_unit.on_read_input)
mbc.connect('write', mbc_unit.on_write)
var _rc = mbc.open(port, params[0], params[1], params[2], params[3], params[4])
mbc.thread_run()
mbc.unit_name = nm
return mbc
func create_modbus(nm) -> sch_3.Sch3:
var unit_sch3: = sch_3.Sch3.new(nm)
return unit_sch3
func _ready() -> void:
@@ -186,18 +155,14 @@ func _ready() -> void:
unit_tcp.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
unit_tcp.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
if proto in MODBUS_PROTO:
var unit_modbus = MODBUS_PROTO[proto].new(unit_name)
var unit_key = settings.get_unit_key(unit_name)
if logger_page:
unit_modbus.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
unit_modbus.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
var mbc = create_modbus(unit_name, unit_modbus)
units_modbus[unit_key] = unit_modbus
units[unit_key] = unit_modbus
mbcs[unit_key] = mbc
if proto in SERIAL_PROTO:
var unit_serial = SERIAL_PROTO[proto].new(unit_name)
@@ -300,10 +265,7 @@ func _process(_delta: float) -> void:
Error.FAILED: emit_signal('socket_error', [unit_serial, serial])
for key in units_modbus:
var unit_modbus = units_modbus[key]
var mbc = mbcs[key]
match unit_modbus.process(tick):
Error.OK: mbc.send_to(unit_modbus.mb_data)
Error.FAILED: emit_signal('socket_error', [unit_modbus, mbc])
unit_modbus.process(tick)
for sock_unit in tcp_sockets:
var sock = sock_unit[0]
var unit_tcp = sock_unit[1]

View File

@@ -1,164 +1,147 @@
class_name sch_3 extends Node
## Модуль Прибора Щ3
const ONLINE_TIMEOUT: int = 5000 ## Время ожидания данных
const REQUEST_PERIOD: int = 1000 ## Переиод запроса, мс
const ONLINE_TIMEOUT = 5000
## Представление прибора Щ3
class Sch3 extends unit.Unit:
enum Sch3Fsm {
READ_INPUT,
READ_HOLDING,
WRITE,
CONNECT }
var mb_addr: = 0 ## Адрес устройства Modbus.
var cmd_state: = CmdState.DONE ## Состояние выполнения текущей команды.
var tick_rx: = 0 ## Время приёма крайнего сообщения.
var tick_tx: = 0 ## Время отправки крайнего сообщения.
var mb_data: Dictionary = {} ## Буфер для записи в регистры модбас
var step_fsm: Sch3Fsm = Sch3Fsm.CONNECT
var base_input_address: int = 0
var regs_input_count: int = 0
var base_holding_address: int = 0
var regs_holding_count: int = 0
var request_period: int = 300
var reconnect_period: int = ONLINE_TIMEOUT
var write_stack: Array
var tick_fsm: int = 0
var mbc: = ModbusClientRtu.new()
var tick_fsm_delta: = reconnect_period
static var json_conv: = JSON.new()
signal resp_input(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов.
signal resp_holding(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения.
signal resp_write() ## Вызывается при получении подтверждения, что команда записи выполнена
signal info_received(msg: String) ## Вызывается при получении информационного сообщения.
signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации.
func _init(nm: String, u: int = 0):
mb_addr = u
func try_connect() -> bool:
var port = settings.UnitProfiles[name][1]
var params = settings.UnitProfiles[name][2]
mbc.thread_stop()
mbc.queue_clear()
mbc.flush()
mbc.close()
var rc = mbc.open(port, params[0], params[1], params[2], params[3], params[4])
if rc != Error.OK:
push_error('%s: не возможно открыть \"%s\" %s' % [name, port, params])
return false
mbc.set_response_timeout(params[5])
mbc.thread_run()
return true
func push_write_holding(regs: Dictionary):
var keys = regs.keys()
keys.sort()
var data: = []
for k in keys:
data.append(regs[k])
write_stack.append([keys[0], data])
func _on_timeout(tick: int) -> void:
if step_fsm == Sch3Fsm.WRITE:
while write_stack.size():
var write_command = write_stack.pop_front()
mbc.request_write(write_command[0], write_command[1])
cmd_state = CmdState.WAIT
tx_tick = tick
step_fsm = Sch3Fsm.READ_INPUT
elif step_fsm == Sch3Fsm.READ_INPUT:
mbc.request_read_input(base_input_address, regs_input_count)
cmd_state = CmdState.WAIT
tx_tick = tick
step_fsm = Sch3Fsm.READ_HOLDING
elif step_fsm == Sch3Fsm.READ_HOLDING:
mbc.request_read(base_holding_address, regs_holding_count)
cmd_state = CmdState.WAIT
tx_tick = tick
step_fsm = Sch3Fsm.WRITE
elif step_fsm == Sch3Fsm.CONNECT:
try_connect()
mbc.request_read(base_input_address, regs_input_count)
cmd_state = CmdState.WAIT
tx_tick = tick
signal write (addr: int, data: Array) ## Вызывается при получении сообщения подтверждения записи
signal read (addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов.
signal read_input (addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения.
signal error(msg: String) ## Вызывается при получении сообщения об исключительной ситуации.
func _init(nm: String):
name = nm
mbc.connect('read', on_read)
mbc.connect('read_input', on_read_input)
mbc.connect('write', on_write)
## Изменяет состояние. Вызывать периодически.[br]
func parse(return_code: Error, base_addr: int, data: Array, code: String):
if return_code == Error.OK:
rx_tick = Time.get_ticks_msec()
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.DONE
emit_signal(code, base_addr, data)
if not online:
online = true
emit_signal('line_changed', online)
step_fsm = Sch3Fsm.WRITE
tick_fsm_delta = request_period
else:
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.FAIL
emit_signal('error', [code, return_code, base_addr, data])
## Изменяет состояние. Вызывается периодически.[br]
## [param tick] - Текущщее время в мс.[br]
## Возвращает [b]Error.OK[/b] - если данные готовы для отправки.[br]
## Возвращает [b]Error.ERR_BUSY[/b] - если данных для отправки нет.[br]
func process(tick: int) -> Error:
if online and ((tick - rx_tick) > ONLINE_TIMEOUT):
online = false
emit_signal('line_changed', self)
if cmd_state == CmdState.WAIT:
if (tick - tx_tick) > ONLINE_TIMEOUT:
cmd_state = CmdState.FAIL
emit_signal('command_fail', self)
var rc = Error.ERR_BUSY
if cmd_state == CmdState.SEND:
tx_tick = tick
cmd_state = CmdState.WAIT
rc = Error.OK
return rc
## Производит разбор принятых данных. Вызывать при приёме данных на сокете.[br]
## [param data] - Данные принятые на сокете.[br]
## [param tick] - Текущщее время в мс.[br]
func parse(message: Dictionary, tick: int) -> bool:
rx_tick = tick
if not online and (message['code'] != 'exception'):
online = true
emit_signal('line_changed', self)
if message.has('code') and message.has('data'):
var rc: = true
var message_code = message['code']
var message_data = message['data']
match message_code:
'resp_holding', 'resp_input':
var addr = int(message_data[0])
var regs = message_data.slice(1)
for i in regs.size():
regs[i] = int(regs[i])
emit_signal(message_code, addr, regs)
'resp_write':
emit_signal(message_code)
'info':
var msg = message['data']
emit_signal('info_received', msg)
'exception':
var msg = message['data']
if online:
if (tick - rx_tick) > ONLINE_TIMEOUT:
online = false
if cmd_state == CmdState.WAIT:
cmd_state = CmdState.FAIL
emit_signal('except_received', msg)
rc = false
_:
var msg: String = 'код команды \"%s\" - не распознан' % message_code
cmd_state = CmdState.FAIL
emit_signal('parse_failed', msg)
rc = false
if (cmd_state == CmdState.WAIT) and rc:
cmd_state = CmdState.DONE
emit_signal('command_done')
elif (cmd_state == CmdState.WAIT) and (not rc):
cmd_state = CmdState.FAIL
emit_signal('command_fail', self)
return true
## Отправляет команду "записать в регистры".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Данные для записи в регистры от начального адреса.[br]
func write(addr: int, data: Array) -> bool:
if cmd_state != CmdState.DONE: return false
mb_data = {'code': 'write', 'data': [addr] + data, 'unit': mb_addr}
cmd_state = CmdState.SEND
return true
## Отправляет команду "читать регистры хранения".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Количество регистров от начального адреса.[br]
func read_holding(addr: int, count: int = 1) -> bool:
if cmd_state != CmdState.DONE: return false
mb_data = {'code': 'read_holding', 'data': [addr, count], 'unit': mb_addr}
cmd_state = CmdState.SEND
return true
## Отправляет команду "читать регистры входов".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Количество регистров от начального адреса.[br]
func read_input(addr: int, count: int = 1) -> bool:
if cmd_state != CmdState.DONE: return false
mb_data = {'code': 'read_input', 'data': [addr, count], 'unit': mb_addr}
cmd_state = CmdState.SEND
return true
emit_signal('command_fail', name)
emit_signal('line_changed', self)
step_fsm = Sch3Fsm.CONNECT
tick_fsm_delta = reconnect_period
if (tick - tick_fsm) > tick_fsm_delta:
tick_fsm = tick
_on_timeout(tick)
return Error.ERR_BUSY
## Принимает результат команды "читать регистры хранения".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
## [param tick] - Время приёма пакета.[br]
func on_read(return_code, base_addr, data):
var tick = Time.get_ticks_msec()
var msg: Dictionary
if return_code == 0:
msg['code'] = 'resp_holding'
msg['data'] = [base_addr] + data
else:
msg['code'] = 'exception'
parse(msg, tick)
func on_read(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'read')
## Принимает результат команды "читать регистры входов".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
## [param tick] - Время приёма пакета.[br]
func on_read_input(return_code, base_addr, data):
var tick = Time.get_ticks_msec()
var msg: Dictionary
if return_code == 0:
msg['code'] = 'resp_input'
msg['data'] = [base_addr] + data
else:
msg['code'] = 'exception'
parse(msg, tick)
func on_read_input(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'read_input')
## Принимает результат команды "записать в регистры".[br]
## [param return_code] - Код выполнения команды.[br]
## [param base_addr] - Начальный адрес регистров.[br]
## [param data] - Данные прочитанные из регистров.[br]
## [param tick] - Время приёма пакета.[br]
func on_write(return_code, _base_addr, _data):
var tick = Time.get_ticks_msec()
var msg: Dictionary
msg['data'] = 'resp_write'
if return_code == 0:
msg['code'] = 'resp_write'
else:
msg['code'] = 'exception'
parse(msg, tick)
func on_write(return_code: Error, base_addr: int, data: Array):
parse(return_code, base_addr, data, 'write')

View File

@@ -5,11 +5,11 @@ class Unit extends Object:
## Состояние автомата выполнения команды.
enum CmdState {
UNCK, ## Номер команды не ининциирован.
SEND, ## Буфер готов для отправки.
WAIT, ## Ожидание выполнения.
DONE, ## Команда выполнена.
FAIL ## Команда не выполнена.
UNCK, ## Номер команды не ининциирован.
SEND, ## Буфер готов для отправки.
WAIT, ## Ожидание выполнения.
DONE, ## Команда выполнена.
FAIL, ## Команда не выполнена.
}
signal line_changed(unit) ## Вызывается при изменении состояния связи
@@ -18,6 +18,7 @@ class Unit extends Object:
signal parse_failed(unit) ## Вызывается при обнаружении ошибки во входных данных
signal data_received(data: PackedByteArray) ## Вызывается по приёму данных
var cmd_state = CmdState.UNCK ## Состояние выполнения команды
var tx_data: = PackedByteArray() ## Буфер для отправки.
var tx_len: int = 0 ## Длина последнего отправленного пакета.
var tx_tick: int = 0 ## Тик-время отправки буфера
@@ -25,4 +26,4 @@ class Unit extends Object:
var online: bool = false ## Состояние подключения устройства
var name: String = '<без имени>' ## Уникальное имя устройства
func _init(nm) -> void: self.name = nm
func _to_string() -> String: return String('устройство: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]])
func _to_string() -> String: return String('<\"%s\", %s>' % [self.name, ['отключен', 'на связи'][int(online)]])

View File

@@ -29,17 +29,16 @@ class YaU07 extends unit.Unit:
var cmd_num_rx: = 0 ## Номер команды принятый
var cmd_num_tx: = 0 ## Номер команды переданный
var cmd_state = CmdState.UNCK ## Состояние выполнения команды
var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07
var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07
var cmd_retry = RETRY_COUNT ## Счётчик оставшихся попыток выполнить команду
var cmd_retry: = RETRY_COUNT ## Счётчик оставшихся попыток выполнить команду
var cmd_code_rx = 0 ## Код последней выполненой команды
var cmd_code_tx = 0 ## Код последней отправленной команды
var cmd_tick_tx = 0.0 ## Время последней отправки команды
var cmd_tick_rx = 0.0 ## Время последнего приёма команды
var cmd_tick_tx: = 0 ## Время последней отправки команды
var cmd_tick_rx: = 0 ## Время последнего приёма команды
var status: = PackedByteArray() ## Поле "состояние прибора"
var isa_ports = {} ## Результат выполнения команды "читать порт"
var isa_block = {} ## Результат выполнения команды "читать массив из порта"
var isa_ports: = {} ## Результат выполнения команды "читать порт"
var isa_block: = {} ## Результат выполнения команды "читать массив из порта"
var flash_data: = PackedByteArray() ## Данные прочитанные из Flash
var flash_len: = 0 ## Длинна данных прочитанных из Flash
@@ -99,14 +98,14 @@ class YaU07 extends unit.Unit:
tx_data.encode_u16(8, 0)
tx_data.encode_u16(10, len(fl_data))
tx_len = 11 + len(fl_data) * 2
for i in range(len(fl_data)):
for i in len(fl_data):
tx_data.encode_u16(12 + i * 2, fl_data[i])
elif cmd_code == CmdCode.WRITE_FLASH_MP550:
tx_data.encode_u8(7, id_sector)
tx_data.encode_u16(8, 0)
tx_data.encode_u16(10, len(fl_data) * 2)
tx_len = 12 + len(fl_data) * 2
for i in range(len(fl_data)):
for i in len(fl_data):
tx_data.encode_u16(12 + i * 2, fl_data[i])
elif cmd_code == CmdCode.READ_FLASH:
tx_len = 11
@@ -167,7 +166,6 @@ class YaU07 extends unit.Unit:
block_len /= 2
tx_data[6] = cmd_code
tx_data.encode_u16(7, block_len)
tx_data.encode_u16(9, int(port[0]))
cmd_state = CmdState.SEND
cmd_code_tx = cmd_code
@@ -178,7 +176,7 @@ class YaU07 extends unit.Unit:
or (cmd_state == CmdState.SEND) \
or (cmd_state == CmdState.UNCK):
return false
if not (cmd_code == CmdCode.LOAD_EMS_DONE):
if cmd_code != CmdCode.LOAD_EMS_DONE:
return false
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
tx_data.encode_u16(0, cmd_retry)