Host Engineering Forum
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
June 23, 2018, 02:37:11 pm


Login with username, password and session length


Pages: [1] 2 3 ... 5
  Print  
Author Topic: SS memory and pointers  (Read 12050 times)
plcnut
Hero Member
*****
Posts: 779



« on: October 02, 2012, 06:50:18 pm »

Maybe I'm going about this the wrong way, but I am trying to use the STRSUB instruction in a for loop to extract individual pieces of data (6 digit alphanumeric part numbers)  from a rather large STREAMIN (up to 550 bytes), and place the part numbers into individual strings. (This is part of a system that will sort products with barcodes on a conveyor, and divert them to a ten station packing section.) My problem is that I wanted to use a pointer (SS(v0)) in the output string of the STRSUB, but Do-more Designer won't let me. What am I doing wrong? Thank you in advance for the help! BTW the software is great so far Smiley
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
plcnut
Hero Member
*****
Posts: 779



« Reply #1 on: October 02, 2012, 07:22:05 pm »

 Embarrassed I guess I should read the instructions a little closer... the pointer must be in BRACKETS not parenthesis.
Thanks guys.  Grin
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
franji1
Bit Weenie
Host Moderator
*****
Posts: 2313



WWW
« Reply #2 on: October 02, 2012, 10:36:07 pm »

I wrote a tokenization function that took a while to get working right.  It assumes the tokens are separated by white space, then sticks them in a new user data-block of STRINGs I called Token, so Token0 is the first token, Token1 is the second token, up to 10 tokens (Token9). It uses a repeat/until (maybe while?).  It doesn't convert any of the tokens to integers, but it wouldn't be that difficult to take the output of this "Tokenize" TASK to do that step.  Is this something that would be helpful, or do you have it working?
Logged

plcnut
Hero Member
*****
Posts: 779



« Reply #3 on: October 03, 2012, 06:53:27 am »

If you don't mind sharing, I would really like to have a look.
I think I have mine like I want it for receiving the data and entering it into tables, and I'm happy so far with how the program is organized, but I have some comparing to do that I haven't figured out yet. I will be receiving up to 10 orders of varying sizes at a time, each order is entered into a string block, I have to be able to make 4 separate lists from these orders, based on the picking sections, and organized by part numbers. If there are multiples of the same part numbers, I need to either put them together on the list, or add a quantity column to my table.
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
BobO
Host Moderator
*****
Posts: 4105


Yes Pinky, Do-more will control the world!


« Reply #4 on: October 03, 2012, 08:41:38 am »

As you finish this up, I would love to hear your experience with Do-more, with particular emphasis on how well the instruction set did the job and how well you could manage complexity. We still have very little feedback from actual applications.
Logged

"We would rather apologize to 20% for what we chose not to do, than to apologize to 100% for what we did poorly." -BobO
plcnut
Hero Member
*****
Posts: 779



« Reply #5 on: October 03, 2012, 09:09:49 am »

This is a first for me to deal with large amounts of data coming in, and so far it has been really smooth and organized with the program. Way easier than DL!
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
franji1
Bit Weenie
Host Moderator
*****
Posts: 2313



WWW
« Reply #6 on: October 03, 2012, 10:03:06 am »

I just copied the code-block (right click on Tokenize task in my Project Browser to bring up context menu, selected Copy Code Block), then pasted it below.  I would definitely recommend IMPORTING this into a NEW PROJECT (File->Import->Project) and then tweaking it, then copy/pasting it into YOUR project.

For example, I use SS1 as the "Line" (the input to the Tokenize function).  You may want to use a different source STRING element.  It's a little heavy on documentation, but that's a good thing.  Grin  This includes symbolic constants (e.g. NEVER_YIELD is the decimal constant 65,535) They're still a constant, but have a human readable name).  There's also a nickname for an array index (V100).

Also, my Tokens block of STRINGs is STRING32, meaning they are up to 32 characters long, so no single token can be longer than 32 characters.  You may want to tweak that.

So, before you do ENTASK Tokenize from the "calling" code-block with an edge-triggered, just stick the "line" into SS1.  Then look at Tokenize.Done (it probably will take multiple scans) and look at V100 to see how many tokens there are in the Tokens STRING data-block, then look at Tokens0 thru Tokens[V100-1] (although you can't do negative offsets, just positive offsets, e.g. R[V10+6]), so you'll need to "calculate" the last index (V100-1) and stick that in another V.

Let me know if you have any problems importing it or if you have any questions on its behavior.


Code:
// Do-more Designer Clip   Source Project: C:\Do-more Designer\Projects\~DmD11    Format: Do-more Designer 2.00+  DO-MORE Ladder
PLC H2-DM1E

$TSK Tokenize

#BEGIN COMMENT
"Support AT RUNTIME an unknown maximum number of tokens (see Tokens STRING data block)."
""
"Copy command line string to a ""working"" RemainderOfLine string which we will extract tokens from."
""
"Initialize our loop index (index to Tokens array)"
""
"Initialize our LoopToggle bit to ON (necessary in order to process EDGE-TRIGGED instructions from INSIDE a LOOP within the SAME LADDER SCAN)."
""
"Clear the White Space Found/Not Found flags."
#END

STRCLEAR Tokens0 D99
MEMCOPY SS1 SS99 0x20000 1
MOVE 0 V100
SET C1
RSTR C98 C99

#BEGIN COMMENT
"Just in case somebody has messed with this task's .TimeSlice member value and made me  NEVER yield, let me yield every 100 micro seconds during this ""time consuming"" string manipulation/tokenization code."
#END

STRE Tokenize.TimeSlice NEVER_YIELD
MOVE 100 Tokenize.TimeSlice

#BEGIN COMMENT
"This looks like an infinite loop, but the loop termination logic is INSIDE the loop (look for BREAK statement)"
#END

WHILE ST1

#BEGIN COMMENT
"If there's no more tokens to process, we're done."
"Or if the number of tokens in this line exceeds our capacity, we're done too."
#END

STRE SS99.Length 0
ORGE V100 D99
BREAK

#BEGIN COMMENT
"Because we're dealing with edge-triggered instructions inside a loop (this is the cause of all those PROGRAM CHECK WARNINGS!), just do this work ""every other time"" through the loop.  The LoopToggle bit makes this a little easier."
#END

STR C1
MOVE 0 D97
STRFIND SS99 0x2 D97 C99 C98 """ $09$0D$0A"""

#BEGIN COMMENT
"If we found whitespace, extract everything up to (but not including) the space and put it in the current Token."
""
"Since we're only executing REAL logic ""every other time"" through this loop because of the edge-triggered instructions, actively CLEAR the White Space Found flag."
""
"Now remove the extracted token from the line.  We also don't want the found White Space to be included, so increment the White Space Index value to move PAST the white space character, then use that as the ""starting point"" of the ""remainder of the line""."
""
"Conditionally, we want to ONLY use tokens that are NOT empty (e.g. a line with 5 spaces together, we need to ""eat"" those).  So, if the extacted token is empty, do NOT bother incremementing our ""current token"" index.  Code-wise, that means if we DO have a token string (i.e. its length is > 0), go ahead and increment the current index of our Tokens array."
#END

STR C99
STRSUB SS99 0 0x0 D97 Tokens[V100]
RST C99
INC D97
STRSUB SS99 D97 0x0 -1 SS99
ANDGT Tokens[V100].Length 0
INC V100

#BEGIN COMMENT
"If White Space was NOT found, that means that we're on the last token, all the way to the end of the line.  So just put the Remainder of the Line into the current Token."
""
"One of our termination conditions is that there's no more work to do (Remainder of Line is empty), since we know we just processed our last token, just clear the Remainder of Line string!"
""
"For completeness, reset the White Space NOT Found flag."
""
"Even though we found no white space, we don't want to count empty tokens in our token count, so again, for completeness-sake, increment the token count if there is something in the current token."
#END

STR C98
STRPRINT Tokens[V100] 0x0 "SS99"
STRCLEAR SS99 1
RST C98
ANDGT Tokens[V100].Length 0
INC V100

#BEGIN COMMENT
"Toggle our Loop Toggle bit!"
#END

STRN C1
OUT C1

WEND

#BEGIN COMMENT
"Edge Triggered TASKs are like subroutines, once the program counter reaches the bottom, the task is done!  No EXIT to call.  Even this END statement is optional (if END does not exist, the end is the last non-NOP).  But the END coil can be used to divide logic between ""used vs. unused code"".  Here, I needed it so I could have this rung comment (you should not put rung comments on trailing NOP rungs since they technically do not exist)."
#END

END

$TSKEND Tokenize

#BEGIN MEM_CONFIG
 Tokens STRING32 decimal 10 -1
 Tokenize TASK  0
#END

#BEGIN ELEMENT_DOC
"C98","WSNotFound","",""
"SS99","RemainderOfLine","",""
"C99","WSFound","",""
"D97","WSIndex","",""
"V100","TokenizeIndex0","",""
"SS1","Line","",""
"D99","MaxNumTokens","",""
"C1","LoopToggle","",""
"SK","NEVER_YIELD","65535",""
#END

Logged

plcnut
Hero Member
*****
Posts: 779



« Reply #7 on: October 04, 2012, 11:54:06 am »

Thank you franji1,
I look forward to importing your code later today to have a look.
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
plcnut
Hero Member
*****
Posts: 779



« Reply #8 on: October 06, 2012, 12:24:31 pm »

I like your tokenize task franji1, it is similar to what I was doing, except I was extracting the data and updating a pointer to move further into the string, versus cutting the data out of the end like yours, Thank you Smiley
 I ran into a problem with my application though... I don't have experience with importing data from a pc over rs232, but some of the orders I will be receiving may total up to 2800 individual memory locations, (1400 6 digit Alphanumeric product numbers, 1400 4 digit integer product quantities). I'm still waiting on the IT dept. for an exported .csv file from the system to see what it will actually look like.
My problem is, how do I get that much data into my system, and am I crazy to be trying? (when they asked me to start this project, I understood it to be MUCH smaller orders ie 15 items per order average)
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
franji1
Bit Weenie
Host Moderator
*****
Posts: 2313



WWW
« Reply #9 on: October 06, 2012, 01:49:58 pm »

Is your question about how to write a program on the PC to send data to a PLC, or is it about how to store the records in the PLC?

I can answer the second question very easily - no problem.  I just allocated a new STRING data block 1400 in length called ProdName, each STRING max 8 characters long (it has to align on a DWORD boundary, since you need 6 chars, it had to be 8 ).  Then allocated a new UNSIGNED WORD data block 1400 in length called ProdQuant (range 0-65535).  You may want to bump that up to 1500, just in case.

Anyway, the unused memory from a default H2-DM1E (DM1 would be the same) went down from 159,072 to 139,472 bytes (so this used up a measely ~30K ~20K).

So, the index in one data-block corresponds to the matching item in the other, e.g. you found a matching part number ABC123 at index 599 in ProdName (i.e. ProdName599 == "ABC123"), then ProdQuant599 is 45, meaning ABC123's quantity is 45.

The first question, maybe write a VB application that dumps a "line" from the CSV in the form of "ABC123,45<CR><LF>" out the PC's serial port into a General Purpose serial port (internal or H2-SERIO port), so you can easily "add" the rows to your data blocks in the Do-more PLC (or lookup in ProdName then add that quantity to existing quantity in ProdQuant at the same index???).
« Last Edit: October 06, 2012, 01:59:09 pm by franji1 » Logged

BobO
Host Moderator
*****
Posts: 4105


Yes Pinky, Do-more will control the world!


« Reply #10 on: October 06, 2012, 01:53:49 pm »

I was just doing the same math...you'll have plenty of room for the buffers. At 115200, it should only take a couple of seconds to transfer the data, and if it could be Ethernet instead of serial, much quicker than that. I honestly think you can do this no problem, and actually, our tasking makes it very easy to spread the work out over many scans, thus reducing the hit to the scantime.

Logged

"We would rather apologize to 20% for what we chose not to do, than to apologize to 100% for what we did poorly." -BobO
plcnut
Hero Member
*****
Posts: 779



« Reply #11 on: October 06, 2012, 04:09:46 pm »

Thanks guys.

I was trying to set up the serial port buffer and it had a maximum of 1024 bytes(if I am remembering correctly from yesterday), at a large order of 1400 part numbers, that would require a larger buffer than I can set up. Am I misunderstanding the buffer? Or can I set up a data buffer to use a Block versus a String? Or maybe I am misunderstanding the amount of ASCII data in a byte, a byte will only hold 2 ASCII charachters right?

Bobo, I would be happy to use the Ethernet port for the data, it would be easier than the serial from a hardware standpoint I'll just have to study into it...

Thank you for your time.
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
BobO
Host Moderator
*****
Posts: 4105


Yes Pinky, Do-more will control the world!


« Reply #12 on: October 06, 2012, 04:24:31 pm »

The buffer is just the number of bytes that can be read at once...in one call to a STREAMIN or PACKETIN instruction. You would not blindly transfer tens of thousands of bytes without some form of packetizing or error checking, so I would expect that you would be reading a line at a time, or some other quantum of data. The 1K limit per read is quite generous in that context.

One ASCII character is one byte.

From the Do-more programming perspective, Ethernet and serial are about the same level of effort. From the PC app (or whatever) that is sending the data, Ethernet and serial are very different. Assuming that you don't need the full bunch of data very often, serial is more than adequate.

It sounds like you are wandering over into a custom protocol. If you are not familiar with developing such, you might want to seek the help of someone who is. While not 'hard' per se, the learning curve can be pretty frustrating.

It would be pretty straightforward to write a PC based TCP server to provide the data, and use a TCP Client device in Do-more to connect and download the information.
Logged

"We would rather apologize to 20% for what we chose not to do, than to apologize to 100% for what we did poorly." -BobO
plcnut
Hero Member
*****
Posts: 779



« Reply #13 on: October 11, 2012, 07:04:02 pm »

BobO,

I just spoke with the IT guy.
He says if I can do an HTTP request, that would be the best way for him to provide the data. Serial may be problematic. So it sounds like the custom protocol may be the way to go.

I think we are looking at something like this:

OPENTCP, (ip address, port no.)

STREAMOUT, (get/put, etc. in text form from a string structure)

STREAMIN, (place received text into string structure)

CLOSE, (close tcp connection)

Process received data...

Am I getting close?
I hope that he can get a dummy server set up that I can practice sending some requests and see how it will actually work.
Thanks again for your help guys!!!
Logged

Circumstances don't determine who we are, they only reveal it.

~Jason Wolthuis
BobO
Host Moderator
*****
Posts: 4105


Yes Pinky, Do-more will control the world!


« Reply #14 on: October 11, 2012, 07:57:44 pm »

You will likely have many STREAMOUT/STREAMIN pairs in a protocol, but yes, those are the correct functions in the correct order.

Some additional thoughts:
1. It is not necessary to use string structures. If your data is primarily binary, you can allocate a byte buffer and access the individual elements directly.
2. Build your client protocol in a dedicated program block and use stage programming. Trust me on this, even if you are not normally a stage guy.
3. To simplify debug, push input and output strings out to DM Logger using STREAMOUT and the DMLogger device. It makes a very convenient protocol analyzer.
4. And have fun. Writing protocols can be frustrating, just relax and don't be in too much of a hurry.
Logged

"We would rather apologize to 20% for what we chose not to do, than to apologize to 100% for what we did poorly." -BobO
Pages: [1] 2 3 ... 5
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines

Valid XHTML 1.0! Valid CSS! Dilber MC Theme by HarzeM