OpenCOBOL Complex ODO (OCCURS DEPENDING ON) - gnucobol

I am new to COBOL(and OpenCOBOL) and my question is about "complex-odo" (OCCURS...DEPENDING ON) in OpenCOBOL.
I used 1.0 on following code
......
01 W-PTDO-PROC-TBL.
05 W-PTDO-PROC-ENTRY OCCURS 0 TO 450 TIMES
DEPENDING ON W-PTDO-PROC-MAX
INDEXED BY W-PTDO-PROC-INDX.
10 W-PTDO-PROC-APC PIC X(05).
10 W-PTDO-PROC-LNSUB PIC S9(07) COMP-3.
10 W-PTDO-PROC-KEY.
15 W-PTDO-PROC-WA-OFFSET PIC 9(08)V99.
15 W-PTDO-PROC-UNITS PIC 9(09).
10 W-PTDO-PROC-DEVICE-CNT PIC 9(03).
10 W-PTDO-PROC-DARRAY OCCURS 0 TO 450 TIMES
DEPENDING ON W-PTDO-DARRAY-MAX
INDEXED BY W-PTDO-DARRAY-INDX.
15 W-PTDO-PROC-DHCPCS PIC X(05).
10 W-PTDO-DARRAY-SIZE PIC 9(03).
10 W-PTDO-PROC-TOT-DCHRGS PIC 9(10)V99.
10 W-PTDO-PROC-TOT-DUNITS PIC 9(05).
10 W-PTDO-PROC-USED PIC X(01).
......
and cobc returns with this error msg:
Error: 'W-PTDO-PROC-ENTRY' cannot have the OCCURS clause due to 'W-PTDO-PROC-DARRAY'
And above error msg is issued from field.c where I found this comment
/* the data item that contains a OCCURS DEPENDING clause shall not be subordinate to a data item that has the OCCURS clause */
Is there anyway to make OpenCOBOL support this "complex-odo"?
My above code snippet, with "OCCURS DEPENDING" nested under a higher level "OCCURS" clause, seems to be a well-defined "complex-odo" according to appendix of IBM's COBOL Programming Guide.
Thank you,
Billy Rong

You cannot have a variable length array (OCCURS DEPENDING ON) inside another array!
The processing required is just too complex. If the length of the inner array item was allowed to vary, the only possible way to calculate the start of the Nth entry of the outer array is to sequentially access each inner member from 1 to N and use the DEPENDING ON count to work out its length, and, hence the start of the next array entry.

Related

How do I interpret a python byte string coming from F1 2020 game UDP packet?

Title may be wildly incorrect for what I'm trying to work out.
I'm trying to interpret packets I am recieving from a racing game in a way that I understand, but I honestly don't really know what I'm looking at, or what to search to understand it.
Information on the packets I am recieving here:
https://forums.codemasters.com/topic/54423-f1%C2%AE-2020-udp-specification/?tab=comments#comment-532560
I'm using python to print the packets, here's a snippet of the output, which I don't understand how to interpret.
received message: b'\xe4\x07\x01\x03\x01\x07O\x90.\xea\xc2!7\x16\xa5\xbb\x02C\xda\n\x00\x00\x00\xff\x01\x00\x03:\x00\x00\x00 A\x00\x00\xdcB\xb5+\xc1#\xc82\xcc\x10\t\x00\xd9\x00\x00\x00\x00\x00\x12\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$tJ\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01
I'm very new to coding, and not sure what my next step is, so a nudge in the right direction will help loads, thanks.
This is the python code:
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 20777
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(4096)
print ("received message:", data)
The website you link to is describing the data format. All data represented as a series of 1's and 0's. A byte is a series of 8 1's and 0's. However, just because you have a series of bytes doesn't mean you know how to interpret them. Do they represent a character? An integer? Can that integer be negative? All of that is defined by whoever crafted the data in the first place.
The type descriptions you see at the top are telling you how to actually interpret that series of 1's and 0's. When you see "unit8", that is an "unsigned integer that is 8 bits (1 byte) long". In other words, a positive number between 0 and 255. An "int8" on the other hand is an "8-bit integer", or a number that can be positive or negative (so the range is -128 to 127). The same basic idea applies to the *16 and *64 variants, just with 16 bits or 64 bits. A float represent a floating point number (a number with a fractional part, such as 1.2345), generally 4 bytes long. Additionally, you need to know the order to interpret the bytes within a word (left-to-right or right-to-left). This is referred to as the endianness, and every computer architecture has a native endianness (big-endian or little-endian).
Given all of that, you can interpret the PacketHeader. The easiest way is probably to use the struct package in Python. Details can be found here:
https://docs.python.org/3/library/struct.html
As a proof of concept, the following will interpret the first 24 bytes:
import struct
data = b'\xe4\x07\x01\x03\x01\x07O\x90.\xea\xc2!7\x16\xa5\xbb\x02C\xda\n\x00\x00\x00\xff\x01\x00\x03:\x00\x00\x00 A\x00\x00\xdcB\xb5+\xc1#\xc82\xcc\x10\t\x00\xd9\x00\x00\x00\x00\x00\x12\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$tJ\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
#Note that I am only taking the first 24 bytes. You must pass data that is
#the appropriate length to the unpack function. We don't know what everything
#else is until after we parse out the header
header = struct.unpack('<HBBBBQfIBB', data[:24])
print(header)
You basically want to read the first 24 bytes to get the header of the message. From there, you need to use the m_packetId field to determine what the rest of the message is. As an example, this particular packet has a packetId of 7, which is a "Car Status" packet. So you would look at the packing format for the struct CarStatus further down on that page to figure out how to interpret the rest of the message. Rinse and repeat as data arrives.
Update: In the format string, the < tells you to interpret the bytes as little-endian with no alignment (based on the fact that the documentation says it is little-endian and packed). I would recommend reading through the entire section on Format Characters in the documentation above to fully understand what all is happening regarding alignment, but in a nutshell it will try to align those bytes with their representation in memory, which may not match exactly the format you specify. In this case, HBBBBQ takes up 2 bytes more than you'd expect. This is because your computer will try to pack structs in memory so that they are word-aligned. Your computer architecture determines the word alignment (on a 64-bit computer, words are 64-bits, or 8 bytes, long). A Q takes a full word, so the packer will try to align everything before the Q to a word. However, HBBBB only requires 6 bytes; so, Python will, by default, pad an extra 2 bytes to make sure everything lines up. Using < at the front both ensures that the bytes will be interpreted in the correct order, and that it won't try to align the bytes.
Just for information if someone else is looking for this. In python there is the library f1-2019-telemetry existing. On the documentation, there is a missing part about the "how to use" so here is a snippet:
from f1_2020_telemetry.packets import *
...
udp_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udp_socket.bind((host, port))
while True:
udp_packet = udp_socket.recv(2048)
packet = unpack_udp_packet(udp_packet)
if isinstance(packet, PacketSessionData_V1): # refer to doc for classes / attribute
print(packet.trackTemperature) # for example
if isinstance(packet, PacketParticipantsData_V1):
for i, participant in enumerate(packet.participants):
print(DriverIDs[participant.driverId]) # the library has some mapping for pilot name / track name / ...
Regards,
Nicolas

7-bit circular buffer with bit option flag in a byte

I'm hoping someone can help me on this.
I made a function for an 8051 microcontroller that accepts input from a button and I'm using a cyclic buffer of 8 bits to store key states so I can make debouncing not an issue.
The code to store data in the buffer and to check for one key is here:
VALIDPRESS equ 0Fh ;0Fh = detect as valid if key held somewhat
CYCLICBUFFER equ 10h ;10h is a randomly picked value as example
mov R0,#CYCLICBUFFER ;memory location for key buffer
mov C,KEY ;KEY = GPIO pin button is attached to
mov A,#R0 ;A = data found at address CYCLICBUFFER
rlc A ;Shift in new detected value
mov #R0,A ;Store updated byte to address CYCLICBUFFER
cjne A,#VALIDPRESS,nokey ;See if buffer contains bits in right order
;If it does, the key is valid
nokey:
There's only one thing... I have very limited memory available and I think I can somehow use one bit from the 8-bit buffer to store a flag. I want that flag to represent if that specific key is allowed to be held down or to be pressed only.
I'll show in the left column how data flows into my buffer as key presses are detected. What I'd like to have happen is whats shown in the right column below.
Let x equal unknown value, and a through m represent new button scan values 1 through 13 respectively, and let Z equal the custom flag that is never allowed to be changed by the keyscan routine.
Loop count, Current data flow, Desired data flow
0 xxxxxxxx Zxxxxxxx
1 xxxxxxxa Zxxxxxxa
2 xxxxxxab Zxxxxxab
3 xxxxxabc Zxxxxabc
4 xxxxabcd Zxxxabcd
5 xxxabcde Zxxabcde
6 xxabcdef Zxabcdef
7 xabcdefg Zabcdefg
8 abcdefgh Zbcdefgh
9 bcdefghi Zcdefghi
10 cdefghij Zdefghij
11 defghijk Zefghijk
12 efghijkl Zfghijkl
13 fghijklm Zghijklm
Is there an easy way to solve this without using lots of memory or lots of clock cycles?

How can I debug a Fortran READ/WRITE statement with an implicit DO loop?

The Fortran program I am working is encountering a runtime error when processing an input file.
At line 182 of file ../SOURCE_FILE.f90 (unit = 1, file = 'INPUT_FILE.1')
Fortran runtime error: Bad value during integer read
Looking to line 182 I see a READ statement with an implicit/implied DO loop:
182: READ(IT4, 310 )((IPPRM2(IP,I),IP=1,NP),I=1,16) ! read 6 integers
183: READ(IT4, 320 )((PPARM2(IP,I),IP=1,NP),I=1,14) ! read 5 reals
Format statement:
310 FORMAT(1X,6I12)
When I reach this code in the debugger NP has a value of 2. I has a value of 6, and IP has a value of 67. I think I and IP should be reinitialized in the loop.
My problem is that when I try to step through in the debugger once I get to the READ statement it seems to execute and then throw the error. I'm not sure how to follow it as it reads. I tried stepping into the function, but it seems like that may be a difficult route to take since I am unfamiliar with the gfortran library. The input file looks OK, I think it should be read just fine. This makes me think this READ statement isn't looping as intended.
I am completely new to Fortran and implicit DO loops like this, but from what I can gather line 182 should read in 6 integers according to the format string #310. However, when I arrive NP has a value of 2 which makes me think it will only try to read 2 integers 16 times.
How can I debug this read statement to examine the values read into IPPARM as they are read from the file? Will I have to step through the Fortran library?
Any tips that can clear up my confusion regarding these implicit loops would be appreciated!
Thanks!
NOTE: I'm using gfortran/gcc and gdb on Linux.
Is there any reason you need specific formatting on the read? I would use READ(IT4, *) where feasible...
Later versions of gfortran support unlimited format reads (see link http://fortranwiki.org/fortran/show/Fortran+2008+status)
Then it may be helpful to specify
310 FORMAT("*(1X,6I12)")
Or for older compilers
310 FORMAT(1000(1X,6I12))
The variables IP and I are loop indices and so they are reinitialized by the loop. With NP=2 the first statement is going to read a total of 32 integers -- it is contributing to the determination the list of items to read. The format determines how they are read. With "1X,6I12" they will be read as 6 integers per line of the input file. When the first 6 of the requested 32 integers is read fron a line/record, Fortran will consider that line/record completed and advance to the next record.
With a format of "1X,6I12" the integers must be precisely arranged in the file. There should be a single blank, then the integers should each be right-justified in fields of 12 columns. If they get out of alignment you could get the wrong value read or a runtime error.

Finding the Raw entrypoint

I want to be able to find out where the code appearing at the entry point comes from by looking at the PE header.
For example, this piece of code is the starting code of my program(401000h)
00401000 >/$ 58 POP EAX ; kernel32.76E93677
00401001 |. 2D 77360100 SUB EAX,13677
00401006 |. BB 4A184000 MOV EBX,<JMP.&kernel32.VirtualProtect>
I want to know where this code comes from. How can I find it without manually scanning my file? (to complete the example, here's an hexdump from the same file, the code now resides at 200h)
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
00000200 58 2D 77 36 01 00 BB 4A 18 40 00
How can I get from my virtual entry point (401000h) to the raw entry point (200h)?
I tried solving it myself of course. But I'm missing something. At first I thought:
.text[ Entrypoint (1000h) - VirtualOffset (1000d) ] = raw entrypoint
since the file alignment = 200, and the raw entry point was at the very start of my .text section, I thought I could use this for all the executables.
Solved, I made stupid mistakes when calculating the raw entry point
.text[ Entry point - Virtual offset ] + File Alignment = Raw entry point (relative to .text section)
To locate the offset in the file by yourself you need to have a look at the _IMAGE_NT_HEADERS structure. From this you can get the IMAGE_OPTIONAL_HEADER where
the member you are interested in ImageBase is. You can change its value with EditBin /REBASE so there is little need to roll your own tool.
For reference how you can determine the entry point via dumpbin.
You can use
dumpbin /headers
dumpbin /headers \Windows\bfsvc
Dump of file \Windows\bfsvc.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
4 number of sections
4A5BBFB3 time date stamp Tue Jul 14 01:13:55 2009
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
OPTIONAL HEADER VALUES
10B magic # (PE32)
9.00 linker version
DE00 size of code
2000 size of initialized data
0 size of uninitialized data
4149 entry point (01004149)
1000 base of code
F000 base of data
1000000 image base (01000000 to 01011FFF)
1000 section alignment
200 file alignment
For the entry point the image base value is relevant. But this is only true for images that are not ASLR enabled. For them a random base address (1 of 128 different ones) is choosen.
The flag that indicates if an image is ASLR enabled is the value 0x40 which is set in DLL characteristics.
8140 DLL characteristics
For svchost.exe for example it is set for older programs it is generally 0.
Yours,
Alois Kraus
Have a look at this thread including an answer with a detailed explanation: Calculating the file offset of a entry point in a PE file
AddressOfRawEntryPoint (in EXE file) = AddressOfEntryPoint + .text[PointerToRawData] - .text[VirtualAddress]

Scancode when I press a key is different. Is Microsoft specification wrong?

I am using Windows XP pro SP3. Standard english keyboard. I live in the USA; never touched the keyboard settings. Stock install. So, when I press check the scancodes my program is returning they are as follows:
A = 30
S = 31
D = 32
F = 33
G = 34
When I check the microsoft specification (page 11 of the document:: http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc ) It says:
A = 31
S = 32
D = 33
F = 34
G = 35
They are off by 1! Any ideas why?
The Microsoft Keyboard Scan Code Specification you quoted has six columns. For the A key:
key location: 31
keyboard: A
scan 1 make: 1E
scan 1 break: 9E
scan 2 make: 1C
scan 2 break: F0 1C
It looks like that "scan 2" set is an alternate hardware scan code that's different from the original IBM PC scan code ("scan 1"). Note that the "key location" is 31 and the "scan 1 make" is 30. This might help explain what you're seeing with the values you originally posted. Perhaps you could try looking at keys such as Esc and ` that are quite different in each set (and not just off by one, which I think is misleading).
You didn't say which API or Windows message you were using to get the scan code values you reported, but if you look in the detailed documentation for whatever you're using you might find more information.
Is the keyboard faulty at the hardware level or there is a problem with the keyboard driver can you ascertain?

Resources