Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing on real machine #1

Closed
WouterElfrink opened this issue Jan 12, 2021 · 13 comments · Fixed by #2
Closed

Testing on real machine #1

WouterElfrink opened this issue Jan 12, 2021 · 13 comments · Fixed by #2
Assignees
Labels

Comments

@WouterElfrink
Copy link

Hello,

I want to read machine data from a iTNC530.

I'm trying to connect to a iTNC530 using pyLSV2 using the code from the Usage section in the README

import pyLSV2
 con = pyLSV2.LSV2('192.168.56.101')
 con.connect()
 print(con.get_versions())
 con.disconnect()

I changed it so it connects to the correct IP-address, but when running the code I get the error NotImplementedError: this case for system parameters is unknown, please send log messages to add:

Looking further in this error I can see that it has to do with message_length == 124: # real machine? not tested!

Have you tested it on a real machine or do you have any advice as to how I could solve this problem ?

Thanks in advance!

@drunsinn
Copy link
Owner

Hello,

thanks for testing! Yes, I am running my code with real machines with a TNC 640 and a TNC 620.

The code is requesting information from the control and the response with a message of a certain length. Our machines always had a length of 120 characters so it worked for me. A document I found mentioned a length of 124 for programming stations but everything I tested had always 120 chars. As I can't decode the message without a sample I added the test for a length of 124 with the message you received. The Java-code I found at https://github.com/tfischer73/Eclipse-Plugin-Heidenhain does some padding to always get 124 characters.
I have just now published version 0.5.2 that does the same and just ignores the last 4 characters. With that you should be able to establish the connection.

As I have said, without any test data I can't be sure if the decoded data is correct. It would be really helpful if you could check if the data matches you machines configuration!

@drunsinn drunsinn self-assigned this Jan 12, 2021
@drunsinn drunsinn added the iTNC label Jan 12, 2021
@drunsinn
Copy link
Owner

Updated package is available via the python package index / pip now. https://pypi.org/project/pyLSV2/#history

@WouterElfrink
Copy link
Author

Thanks for your answer and the updated package !

I did some testing myself and tried the same with decoding the message_length of 124. I got the same results then as I get with your package now. So I think that is the right way to go.

Now when using the command connect the _configure_connection part is giving an Exception: error in communication. I think this has to do with the max_block_length.

When I just use the _llcom.connect part of the connect function and then configure the connection myself (not using the max_block_length) I can login and use the get_versions() command, it then returns the correct values.

I don't know if I can set the max_block_length to a specific value or that it then gives an error. Haven't tried that yet.

Maybe you have some idea as to why this is giving the error and/or know a solution ?

Thanks for the help anyway !

@WouterElfrink
Copy link
Author

When the machine is not running I can read the selected program with get_selected_program just fine and get an output like TNC:/PRG/'Running Program' But when the machine is running it prints the selected program twice. Once with a byte in front of it and once just fine. Like this for example: pTNC:/PRG/'Running Program' TNC:/PRG/'Running Program'.

Sometimes that byte can't be decoded by UTF-8 and it returns the following error UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcd in position 3: invalid continuation byte. I've tried using Latin-1 for the decoding, it then does not give the error but I can't really make much of the first byte.

Do you know why it prints the selected program twice and why with that weird first byte ?

p.s. Is it fine with you if I keep posting my findings here or do you prefer an other way of communication ?

Thanks in advance!

@drunsinn
Copy link
Owner

Thanks again for the fast feedback!
I have taken a quick look at the code, the error you get can have multiple causes. Can you post the log output where it says which block length was read from the control?
Either there is a problem in decoding the system parameters or I am not sending out the correct system command.

The problem with decoding the file name is probably also a result of my lazy approach to decoding the response message. The difference between TNC 640 an iTNC 530 seem to be greater than I would have expected 😅

I will take a look at solving these problems later today, if you could post a debug log file it would be grate!

Feel free to continue posting here, it lets me keep track of the changes I made for certain topics.

Regards,
Max

drunsinn added a commit that referenced this issue Jan 13, 2021
Fix problems mentioned in Issue #1
@drunsinn drunsinn linked a pull request Jan 13, 2021 that will close this issue
@drunsinn
Copy link
Owner

Ok, it really was a problem with me being lazy while implementing reading the program stack. I did my testing for the function get_selected_program() just after switching on the machine, this lead to me thinking there was only one file name surrounded by 0x00. This was obviously wrong! 😅
The byte you saw at the beginning of the string are actually the line number in the currently executed file.

I had to change and rename the function to reflect this.

  • get_selected_program() was renamed to get_program_stack()
  • get_program_stack() now returns a dictionary with three values: line number of execution cursor, selected main program, file that is currently being executed

Depending on the state of the control these values might be zero and/or empty. For example, after power on before the first nc start, the current program is empty.

@WouterElfrink
Copy link
Author

Can you post the log output where it says which block length was read from the control?
Either there is a problem in decoding the system parameters or I am not sending out the correct system command.

Hello Max,

I had some difficulties getting the log file. I'll work on that so that i can post it. But I did read the block length from the control with get_system_parameter()['Max_Block_Length'] and it returns 4096. When I use the connect command it gives an error saying error in communication so I do indeed think that the problem has to do with:

not sending out the correct system command.

Thanks for the update, I'll go and try that !

Wouter

@drunsinn
Copy link
Owner

drunsinn commented Jan 14, 2021

Ok, this seems to have nothing to do with setting of the buffer size but enabling the secure file send option. The log message is/was but I changed it to read differently.

I also went ahead an added a fallback if enabling the secure file send was successful. There probably is some flag where I could check ahead of time but I am not sure which one. Instead of raising an Exception it now disables the secure file send. This seems to be not that big of a deal as it only affects the very last acknowledgment to the control. The latest release (0.5.4) should at least give better log messages to get an idea what went wrong.

To get the log messages just add
import logging
logging.basicConfig(level=logging.DEBUG)
to your script.

@WouterElfrink
Copy link
Author

WouterElfrink commented Jan 15, 2021

Hello Max,

Here you have the log message after running the code

con = pyLSV2.LSV2('IP', PORT, safe_mode=False)
con.connect()

DEBUG:root:Socket successfully created, host 'IP-Address' was resolved to 'IP-Address'
INFO:root:safe mode is off, login and system commands are not restricted. Use with caution!
DEBUG:root:Connected to host 'IP-Address' at port 'Port'
DEBUG:root:telegram to transmit: command A_LG payload length 8 bytes data: bytearray(b'\x00\x00\x00\x08A_LGINSPECT\x00')
INFO:root:login executed successfully for login INSPECT
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x01')
INFO:root:command R_VR executed successfully, received S_VR with 8 bytes payload
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x02')
INFO:root:command R_VR executed successfully, received S_VR with 14 bytes payload
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x03')
INFO:root:command R_VR executed successfully, received S_VR with 19 bytes payload
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x04')
INFO:root:command R_VR executed successfully, received S_VR with 18 bytes payload
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x05')
INFO:root:command R_VR executed successfully, received S_VR with 13 bytes payload
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x06')
WARNING:root:T_ER or T_BD received, an error occurred during the execution of the last command: wrong parameter
DEBUG:root:telegram to transmit: command R_VR payload length 1 bytes data: bytearray(b'\x00\x00\x00\x01R_VR\x07')
WARNING:root:T_ER or T_BD received, an error occurred during the execution of the last command: wrong parameter
DEBUG:root:got version info: {'Control': 'iTNC530', 'NC_Version': '340480 14 SP4', 'PLC_Version': 'iC40V2.1_9/S/ ZM87', 'Options': '%0000111100000001', 'ID': '000013667948'}
DEBUG:root:telegram to transmit: command R_PR payload length 0 bytes data: bytearray(b'\x00\x00\x00\x00R_PR')
INFO:root:command R_PR executed successfully, received S_PR with 124 bytes payload
WARNING:root:messages with length 124 might not be decoded correctly!
DEBUG:root:got system parameters: {'Marker_Start': 12064, 'Markers': 10000, 'Input_Start': 22064, 'Inputs': 1000, 'Output_Start': 23064, 'Outputs': 1000, 'Counter_Start': 24064, 'Counters': 144, 'Timer_Start': 24208, 'Timers': 1000, 'Word_Start': 64, 'Words': 10000, 'String_Start': 25208, 'Strings': 100, 'String_Length': 128, 'Input_Word_Start': 10064, 'Input Words': 1000, 'Output_Word_Start': 11064, 'Output_Words': 1000, 'LSV2_Version': 1, 'LSV2_Version_Flags': 255, 'Max_Block_Length': 4096, 'HDH_Bin_Version': 0, 'HDH_Bin_Revision': 0, 'ISO_Bin_Version': 0, 'ISO_Bin_Revision': 0, 'HardwareVersion': 0, 'LSV2_Version_Flags_Ex': 125, 'Max_Trace_Line': 250, 'Scope_Channels': 0,
'PW_Encryption_Key': 0}
INFO:root:setting connection settings for iTNC530 and block length 4096
DEBUG:root:telegram to transmit: command C_CC payload length 2 bytes data: bytearray(b'\x00\x00\x00\x02C_CC\x00\x07')
DEBUG:root:telegram to transmit: command C_CC payload length 2 bytes data: bytearray(b'\x00\x00\x00\x02C_CC\x00\x13')
WARNING:root:T_ER or T_BD received, an error occurred during the execution of the last command: wrong parameter
DEBUG:root:unknown or unsupported system command
WARNING:root:secure file transfer not supported? use fallback
DEBUG:root:telegram to transmit: command A_LG payload length 5 bytes data: bytearray(b'\x00\x00\x00\x05A_LGFILE\x00')
INFO:root:login executed successfully for login FILE
INFO:root:successfully configured connection parameters and basic logins. selected buffer size is 4096, use secure file send: False
DEBUG:root:logout for login None
DEBUG:root:telegram to transmit: command A_LO payload length 0 bytes data: bytearray(b'\x00\x00\x00\x00A_LO')
INFO:root:logout executed successfully for login None
DEBUG:root:Connection to 'IP-Address' closed
DEBUG:root:Connection to host closed

I hope this is a correct way to post the log output
Wouter

@WouterElfrink
Copy link
Author

Max,

I added the option to read the execution status in my client, I don't know if you want to put that in the package but here is the code:

# Added the execution state const for R_RI
# const for relegram R_RI
R_INFO_EXEC_STATE = 23
R_INFO_SELECTED_PGM = 24
R_INFO_PGM_STATE = 26
# Added the execution states
# known execution states
EXEC_STATE_MANUAL = 0
EXEC_STATE_MDI = 1
EXEC_STATE_PASS_REFERENCES = 2
EXEC_STATE_SINGLE_STEP = 3
EXEC_STATE_AUTOMATIC = 4
EXEC_STATE_UNDEFINED = 5

# added execution mode
def get_execution_status(self):
    """reads the execution status."""
    self.login(login=LSV2.LOGIN_DNC)

    payload = bytearray()
    payload.extend(struct.pack('!H', self.R_INFO_EXEC_STATE))

    result = self._send_recive(
        LSV2.COMMAND_R_RI, LSV2.RESPONSE_S_RI, payload)
    if result:
        exec_state = struct.unpack('!H', result)[0]
        return exec_state
    else:
        logging.error('an error occurred while querying execution state')
    return False

# Added execution status text
@staticmethod
def get_execution_status_text(code):
    """map status code to text"""
    return {LSV2.EXEC_STATE_MANUAL: 'Manual execution',
            LSV2.EXEC_STATE_MDI: 'MDI execution',
            LSV2.EXEC_STATE_PASS_REFERENCES: 'Pass References execution',
            LSV2.EXEC_STATE_SINGLE_STEP: 'Single Step execution',
            LSV2.EXEC_STATE_AUTOMATIC: 'Automatic execution',
            LSV2.EXEC_STATE_UNDEFINED: 'Execution state undefined'}.get(code, 'Unknown Execution state')

Wouter

@drunsinn
Copy link
Owner

Hello Wouter,

first, thank you for the new functions, I will add them in a release later today after I have done some testing!
Feel free to send me your changes via pull requests, they are very welcome!

From the log you posted confirms my suspicion. I can see that the control reports that it doesn't support the command C_CC with payload of 0x0013. This is the command to enable the secure file sending.
The code recovers from the failed command by disabling the secure file sending. I would guess that you can now send and receive files from the control!
You might want to take a look at the test scripts. I will have to write up some examples for file transfer.

Max

@WouterElfrink
Copy link
Author

Hey Max,

I want to read the PLC-memory to wait until a value changes using a WORD, MARKER or DWORD statement.

I sent a command that waits until the program state changes.

I've used the TNCcmd to send this statement and inspected it with Wireshark. I've found that it first makes a login with LOGIN_PLCDEBUG and then sends a command with R_MB (from PC to TNC) and get a response with S_MB (from TNC to PC)

I saw in the .client that the R_MB command was found via bruteforce test, purpose unknown but I didn't see the S_MB command.

Do you know a way how we can implement this reading of the PLC-memory in the code ?

Wouter

@drunsinn
Copy link
Owner

First, I will create a new Issue for reading the PLC values since it is a different topic. I will copy your request and reply there: #3

Second: can you confirm that the reported problem with establishing the connection is fixed? If so, can you close this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants