ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

READ(E) on DSPF, a better way?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • READ(E) on DSPF, a better way?

    Good morning, working on a program that reads a card from a scanner and loads it onto a DSPF, the program does a WRITE, then READ(E) on the display file when the scan field is populated. It seems it gets errors pretty frequently when someone has clocked in in the morning and the screen has sat on that last record for a few hours. I want to make this more reliable on the read of the scanned number, it does get to the DSPF field intact, but for some reason the READ(E) has an error and the logic has the program loop and redisplay. I will be putting a 'READ ERROR - TRY AGAIN' message on this error, but is there a more reliable way to code this?

    ************************************************** *************
    Code:
    FPRBADGL4 IF E K DISK
    FTKMSTRL6 IF E K DISK
    FTMC003D CF E WORKSTN
    f maxdev(*file)
    *
    D SDS
    D SPGM *PROC
    D JOBNAM 244 253
    D USERNM 254 263
    *
    C*================================================ =============
    C*
    C* EXECUTE SCREEN
    C*
    C begin TAG
    C MOVE *BLANKS @IDNUM
    C MOVE *BLANKS SIDNUM 10
    C MOVE *BLANKS @FNAME
    C MOVE *BLANKS @LNAME
    C Z-ADD 0 @DATE
    C Z-ADD 0 @TIME
    *
    C START TAG
    C TIME TIMDAT 12 0
    C MOVEL TIMDAT stime 6 0
    C MOVE TIMDAT sdate 6 0
    C WRITE TMC003R1
    C READ(e) TMC003D
    C IF %error
    C eval @FNAME = 'SCAN ERROR'
    C eval @LNAME = '- TRY AGAIN'
    C GOTO start
    C ENDIF
    C ENDIF
    C MOVE *BLANKS @FNAME
    C MOVE *BLANKS @LNAME
    C Z-ADD 0 @DATE
    C Z-ADD 0 @TIME
    C*
    C *IN01 CASEQ '1' EXIT
    C END
    C*
    C @IDNUM IFNE *BLANKS
    C @IDNUM ANDNE SIDNUM
    *
    C TESTN @IDNUM 50
    C *IN50 IFEQ '0'
    C MOVEL 'INVALID#' @FNAME
    C MOVEL @IDNUM SIDNUM
    C GOTO START
    C ENDIF
    *
    C MOVEL @IDNUM SIDNUM
    C MOVE @IDNUM IDNUM# 9 0
    C IDNUM# CHAIN PRBADGL4 90
    C *IN90 IFEQ '1'
    C MOVEL 'INVALID#' @FNAME
    C MOVEL @IDNUM SIDNUM
    C GOTO START
    C ELSE
    *
    C PRKEY CHAIN TKMSTRL6 91
    C *IN91 IFEQ '0'
    C MOVE FNAME @FNAME
    C MOVE LNAME @LNAME
    C ENDIF
    *
    C TIME TIMDAT 12 0
    C MOVEL TIMDAT @TIME 6 0
    C MOVE TIMDAT @DATE 6 0
    C move @date pdate 6
    C move @time ptime 6
    C MOVE @IDNUM SIDNUM
    C MOVE @IDNUM IDNUMP 9
    C movel jobnam @clock 10
    C* CALL 'TMC003C1'
    C* PARM IDNUMP
    C* PARM @CLOCK
    C* PARM pdate
    C* PARM ptime
    C* GOTO START
    C ENDIF
    c ENDIF
    C*
    C GOTO START
    C*
    C* END MAIN ROUTINE
    C*

    Thanks in advance.
    Last edited by DeadManWalks; May 25, 2016, 01:57 PM.

  • #2
    I thought you always used exfmt RecordFormatName.

    Also, OMG why are there tags, moves and gotos in here. I hope this is maintenance of an old pgm.
    Hunting down the future ms. Ex DeadManWalks. *certain restrictions apply

    Comment


    • #3
      You mention stuff like reading a "card" and "clocking in" that i think could use more explanation. Your RPG code is reading a display file, which usually means a 5250 display. How does this relate to reading a card or clocking in? What sort of "card" are you referring to? If you are interfacing with some sort of special device through a workstation file, then who knows how that device needs to work... so more info would be nice.

      If we're just talking about a regular 5250 display, though... I know of two reasons that you would do a READ(E) <filename> instead of EXFMT

      1) When working with multiple-device files, this is needed. (For example, if the program is controlling multiple terminals at once.) If you are somehow feeding screens from clocks, maybe a single program controls multiple clocks??

      2) When using stuff like WAITRCD(xx) to "time out" the display, this is needed. For example, if you want the RPG code to gain control when the user doesn't type anything for a minute or two, and then display something new before going back to the display or something like that, you can use this technique.

      Both of these techniques also use the MAXDEV(*FILE) keyword that you've coded -- so that would corroborate one of the two techniques listed above.

      The reaaon for the READ(E) here is because when the display times out, that produces an error you want to catch. Likewise, if the user were to submit the screen at exactly the same time as the timeout, it would produce an error. So using READ(E) is a good idea for this type of display. If you have mulitple devices and one is powered off or disconnected, that could also produce an error... so using (E) to catch errors is a good idea.

      It's not clear why this would make things unstable, though. Changing the RPG opcode to use something else like EXFMT shouldn't have any impact at all on stability. More likely, the instability comes from the display sitting open for a long time on an imperfect network connection. That is a normal thing with 5250, it is really sensitive to network errors, it expects perfect connectivity where things never go down or have communication errors. It has never recovered very well from problems.

      Comment


      • #4
        Good morning, yes this is really old type code, it was written after 2000 but the person doing it is retiring and I am taking their place, so almost every program I have worked on since I came on board has goto's and tags and is RPG, not ILE. Crazy.

        Scott, thank you for the breakdown. Yes this is a time clock program that sits and waits for someone to scan a card on a separate scanning device and their card number gets loaded to this screen. If the number is invalid the screen will say that, but there are times when they scan and their number appears but the program doesn't display anything else, so I am thinking it is hitting an error on the READ(E) and going back to the top. The WAITRCD is to refresh the system time on the screen so the user knows what time it is when they clock in/out. From what I have seen so far, there are about 10 places here using this program, all separate jobs on the AS400, so I am not sure about the MAXDEV(*file) setting.

        I have seen some things online about adding error checking on the WRITE, that there may be an issue with buffers. I am looking into that. Here is that link.


        Thanks for all the input.

        Comment


        • #5
          If the WAITRCD is updating the time on the screen, then isn't there a really good chance that it will reach it's timeout value while in the middle of a scan? It sounds like that would cause the problem you're seeing.

          Comment


          • #6
            Hello Scott, it seems that when people are going to lunch that the read errors are happening. Of course there could be many people trying to clock out for lunch but each section has their own job running. They are saying that the first person that tries to clock for lunch has the issue, then anyone after them is fine. I was thinking on the reset to clear the screen fields that have the last badge number, time and employee name.

            Aside from that and the possible error checking on the WRITE, not sure what else to do but display a 'READ ERROR' message to the user.

            Thanks.

            Comment


            • #7
              I was going to add a check of the '01331' code for the wait record being reached and clear all fields after that.

              Comment


              • #8
                The other thing to do is look at the errors that are occurring, see what they are and what the causes are... then you'll have a lot more information with which to decide how best to fix it.

                Comment


                • #9
                  Good morning Scott, there doesn't seem to be anything on the job log of these jobs, I looked on one of them and I just see when the job started, but no details. Sorry if this sounds too stupid, but besides a job being submitted with logging, what other settings would I need to capture any messages?

                  Comment


                  • #10
                    Hmmm.. I don't remember whether the (E) extender suppresses job log messages or not? I don't have time to research this right now. You could try eliminating the (E) extender and using MONITOR instead to trap the error and see if that gives you job log messages.

                    Comment


                    • #11
                      Hello Scott, I put a log file on the WRITE and READ and was capturing the status code as I tested the program.

                      It seems on the READ it hits on a 1331 error, which when I do this command DSPMSGD RANGE(*FIRST *LAST) MSGF(QRNXMSG) DETAIL(*BASIC) and look it up it says "Wait time exceeded for input operation to file". On the DSPF attributes it has a WaitRcd of 60. So if I get this error I will be saying 'Scan error try again" to the user. Is there anything else I can do to this it eliminate the error? The Waitrcd is supposedly for refreshing the screen so the system time is current. This only happens to a specific set of users do not sure what to make of it.

                      Thanks again for your input.

                      Comment


                      • #12
                        Ok, I see what it happening now. If there is not a scan when the screen hits it's 60 second wait, there is a read error 01331. If I do a good scan record and let the screen sit, when the time refreshes the program goes to the READ, goes through my error logic and my message appears on the screen.

                        So how do I code for this? I will clear all the input fields and go back up to my display when there is a refresh, I guess if there is a value in my scanned number field at the time of the error I could say "try again".

                        Thanks.

                        Comment


                        • #13
                          The WAITRCD tells the system to send you the 1331. You say it "refreshes", that is not accurate. What happens is it times out and sends you an error. Your program uses (E) to trap that error and re-display the screen -- so it is your program that 'refreshes' the screen, not the WAITRCD.

                          But, you said there was a problem here -- and all of that sounds normal and expected. What is the problem you are seeing?

                          Comment


                          • #14
                            Hi Scott, there was no message to the user if they tried to scan at the same time this 01331 error was happening. Their scan id would be there, but it would not fill in their name or any other information. So the user didn't know if their scan was good or not. I will put messaging in if they scan when this error is occurring to let them know to try again.

                            The program was not letting the user know it was an error, the program was just redisplaying the screen.

                            Thanks.

                            Comment


                            • #15
                              Your explanation doesn't sit comfortably with me. According to your explanation, it times out every 60 seconds so it can refresh the screen with a new time. Surely that would only take a microsecond or 2 to do? Are you saying that people are always scanning during that miniscule time window? It just seems a little far fetched.
                              It's hard to read the program you've listed - it looks like it has too many ENDIF statements (or have I missed some IFs?). As it's so small, why don't you recode it using modern techniques instead of the awful spaghetti that it is? Also it looks like your %Error addition will trap the timeout but won't update the screen date/time as it should?

                              Comment

                              Working...
                              X