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

[FEATURE] - Radix support when reading tag values #287

Open
1 of 6 tasks
tlf30 opened this issue Jul 3, 2023 · 10 comments
Open
1 of 6 tasks

[FEATURE] - Radix support when reading tag values #287

tlf30 opened this issue Jul 3, 2023 · 10 comments
Labels
enhancement New feature or request

Comments

@tlf30
Copy link
Contributor

tlf30 commented Jul 3, 2023

Type of Feature Request

  • missing feature
    • feature available in another library: please specify
  • change to API
  • enhancing a current feature
  • removal of a broken/unsupported/etc feature
  • other: please specify

Feature Description
I was wondering if it would be possible to get the radix for a symbol from the controller, and perhaps auto format the read values into that radix (maybe like a getter that auto formats the value to a string in the correct radix, or a getter that returns the radix so the developer can format the value correctly)

Possible Solution
Not sure, I took a look at ADF file cip107r07v01.ADF and nothing stood out to me as to if the radix was stored there. I will do some testing later to confirm. Do you know if the radix is stored in the controller and where that might be?

Thanks,
Trevor

@tlf30 tlf30 added the enhancement New feature or request label Jul 3, 2023
@ottowayi
Copy link
Owner

ottowayi commented Jul 3, 2023

This may be possible to reverse engineer, but I have not tried it. Attribute 6 of the Symbol object may be one possible location for it, according to this Micro800 doc it's called software control and it is 32 bits for whatever. I was able to figure out that bit 26 indicated if a tag was an alias to another or not, but that's as far as I went. If it's stored in that, should be able brute force a bunch of tags and see if there is a pattern. As for formatting the value, yeah that's probably possible. Since radix only determines how the value is displayed, I think implementing it as part of the __str__ method on the data types makes the most sense.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 3, 2023

Hmm, I'll take a look today and see what I can find. I think implementing it in __str__ would be great.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 3, 2023

OK, you are correct, it is in software control (attr 6). I will work on decoding which bits to what it means.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 3, 2023

OK, on RSLogix 5000 v20 (I don't have anything newer at home to test with) here are the values for the supported radix. (These are the only radix that RSLogix 5000 v20 has in the drop downs.

Bits 28 - 31 = Radix in Attribute 6 of the symbol class
Hex Values: 
	0x2 = Binary (Default even when no radix can be selected in Studio/RSLogix 5000
	0x3 = Octal
	0x4 = Decimal
	0x5 = Hex
	0x6 = Exponential
	0x7 = Float
	0x8 = ASCII
	0xA = Date/Time

Other values may be used in newer versions of studio, I imagine there may be values used for unsigned datatypes. When I get back to work next week I will do some testing on v35 and see what other radix are supported.

EDIT: Are you sure it was bit 26? That would put it in the middle of the radix bits... Or maybe I have not had enough coffee yet this morning and have my Little/Big Endian backwards. Either way I better drink another cup of coffee and look at it a bit later.

I definitely needed more coffee. I was looking at bits 28-31. I corrected it above.

@ottowayi
Copy link
Owner

ottowayi commented Jul 3, 2023

Oh that's awesome, thanks for getting that so fast.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 3, 2023

No problem. I am more than happy to do testing once your ready.
As mentioned, once I get back to work, I'll check newer versions for more radix types.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 4, 2023

A radix value of 0x0 is used for some built-in types like timers to indicate a null radix.

@ottowayi
Copy link
Owner

ottowayi commented Jul 4, 2023

I added initial support based on what we know currently, you can try it out on the radix branch. I'm not sure I can add it to the __str__ method though, because the tag values are converted into normal python types (int, float, list, etc) after they're read. Instead, after reading the tag, the radix can be looked up and it will be up to the user to decide what to do, e.g.:

tag = plc.read('some_tag')
formatted_tag = format_tag(tag.value, plc.tags[tag.tag]['radix'])

In this fabled rewrite I've been working on, I've created custom objects for all of the CIP data types and it would be much easier to override their __str__ methods then. Like right now the DINT class is never really instantiated, only the encode and decode class methods are used to convert between bytes and ints. It the new system the DINT class is a subclass of int and I have much more control over classes.

We could add it as a property to the Tag class and use it for it's __str__, but that would be a breaking change. That class is a NamedTuple, so adding anymore attributes would break for anyone unpacking it as a tuple (tag_name, value, type, error = tag). V2 will have a number of breaking changes, so I think I'd prefer to do it then (and have a different response dataclass in place of Tag).

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 4, 2023

I think that would be fine for now.
I'll do some testing today on the radix branch with my v16 and v20 ControlLogix controllers. Unfortunately I do not have a micro800 to test on at home (or even at work) to see if the radix is stored differently.

I have not yet figured out where the radix for struct members is stored. Currently I'm looking for that, along with the external access information for struct members. (I would also love to know where the tag descriptions are stored for v21 and above, but I won't be able to test anything until I get back to work and have access to L7x and L8xE controllers)

Also, unrelated to the radix, I am also grabbing if a tag is flagged as constant right now. It is nice to know so that I do not accidently try to write to a constant tag, and I can display to the user that a tag is a constant. Attribute 11 of the symbol class stored as an SINT where 0 is not a constant and 1 is a constant. That may perhaps be another useful piece of information to grab in the future.

@tlf30
Copy link
Contributor Author

tlf30 commented Jul 4, 2023

OK, I've made progress with structs. Still confused on some parts of it, and it is not the same as tags, but I do know how to get the radix.

The radix info is only stored on user created types, and is in the extra payload at the end of the template name ;.
See line 780:

template_name, _ = name.split(";", maxsplit=1)

So the payload of the info is after the semicolon.
The structure is 0x6e, followed by 32bits per top level member. So if a struct member is of a type of another struct, only the member has an entry, not the member's sub-members. Hidden members (who's name starts with ZZZZZZZZZZ do have an entry)

In each 32bit entry, the lowest 4 bits are the radix.
The values I have found are:

Struct Radix:
	BitString/Unknown for ZZZZZZZZZZ members: 0x2
	Binary: 0x3
	Octal: 0x4
	Decimal: 0x5
	Hex: 0x6
	Float: 0x8
	Exponential: 0x7
	ASCII: 0x9
	Date/Time: 0xB

Examples:
image
Payload: 6e 4b41

image
Payload: 6e 4341 4441 4541 4641 4941 4841 4741

image

Payload: 6e 4542 4343 4341 4441 4841 4141 4141 4141

Got Member: ZZZZZZZZZZTEST10
Got Member: B1
Got Member: I1
Got Member: I2
Got Member: F1
Got Member: S1
	Got Member: Val1
	Got Member: Val2
Got Member: S2
	Got Member: ZZZZZZZZZZSTRUCT20
	Got Member: Flag
	Got Member: Data
		Got Member: Val1
		Got Member: Val2
Got Member: S3
	Got Member: ZZZZZZZZZZSTRUCT210
	Got Member: Flag
	Got Member: Data
		Got Member: Val1
		Got Member: Val2

I hope I explained that OK, if you have questions, please let me know.

Interestingly, external access settings for the members are not stored here (I figured they would be). Still on the hunt for them.

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

No branches or pull requests

2 participants