# Conversion routines

The buffers used by daveReadBytes() and daveWriteBytes() will contain a copy of the PLC memory area. This means: If you read from the beginning of DB2, the buffer will contain a byte for byte copy of DB2. The values are the same and in the same order, as what you get when you observe byte variables in Step7. Example:

DB20.DBB0 | 26
DB20.DBB1 | 37
DB20.DBB2 | 48
DB20.DBB3 | 15
DB20.DBB4 | 16

You are free to interpret these values as single bytes or multibyte values,the same way as you can do this in Step7 AWL.:
Also it is unusual, you can load a real value from DB20.DBD1:

    L DB20.DBD1
    L 2.0
    *R

A further complication results from the fact that Siemens PLCs store multibyte values beginning with the most significant byte (big endian) while Intel based PCs store the least significant byte first (little endian).
It is not possible to convert the byte order in the daveReadBytes() or daveWriteBytes() fuctions because the start position of each multibyte value is not known then.
You are free to place such values at arbitrary byte addresses in your PLC program. The same adresses must in turn be used to retrieve values from the copy of PLC memory. If you have a data block DB2 with the following layout:

DBB 0 | BYTE
DBD 1 | DWORD
DBD 5 | REAL

You can retrieve the single values in three ways:
1. From the intenal buffer. After a successful call, an internal pointer points to the 1st byte. Now use daveGetU8(dc) to get the value of the first byte as an unsigned value. The internal buffer pointer is incremented by 1, now pointing to the copy of DBD1. Use daveGetS32(dc) to get the value of the of the next 4 bytes as a signed value. The internal pointer is incremented by 4, now pointing to the copy of DBD5. Use daveGetFloat(dc) to get the value of the next 4 bytes as a single precision float.
2. From the internal buffer, specifying a position. Use daveGetU8at(dc,0) to get the value of the first byte as an unsigned value. Next use daveGetS32at(dc,1) to get the value of the 4 bytes starting at 1 as a signed value. Finally, use daveGetFloatat(dc,5) to get the value of the 4 bytes starting at 5 as a single precision float. You may perform these operation in any order and also repeat them.
3. From a user buffer. Use daveGetU8from(buffer) to get the value of the first byte as an unsigned value. Use daveGetS32from(buffer+1) to get the value of the 4 bytes at buffer+1, i.e. DBD 1, as a signed value. Use daveGetFloatat(buffer+5) to get the value of the 4 bytes starting at buffer+5 as a single precision float, i.e. DBD5.
The conversion functions are named after the bit length and signedness they assume:

int buffer | int buffer+pos | buffer pointer | size | signed | C-return type | Pascal ret type
--- | --- | --- | --- | --- | --- | ---
daveGetU8 | daveGetU8at | daveGetU8from | 8 bit=1 byte | no | int | longint
daveGetS8 | daveGetS8at | daveGetS8from | 8 bit=1 byte | yes | int | longint
daveGetU16 | daveGetU16at | daveGetU16from | 16 bit=2 byte | no | int | longint
daveGetS16 | daveGetS16at | daveGetS16from | 16 bit=2 byte | yes | int | longint
daveGetU32 | daveGetU32at | daveGetU32from | 32 bit=4 byte | no | unsigned int | longint
daveGetS32 | daveGetS32at | daveGetS32from | 32 bit=4 byte | yes | int | longint
daveGetFloat | daveGetFloatat | daveGetFloatfrom | 32 bit=4 byte | yes | float | single

There had been an older set of those functions named after data types, e.g. daveGetDWORD(). Those functions should not be used any more, as there names might be misunderstandable between PLC and C or other programming languages. They are still supported for compatibility with older versions. These functions had been inlined in earlier versions but are now not inlined by default, because other languages than C cannot make use of inline definitions in a C header file.

#### Notes:

Most commercial libraries handle the conversion issue differently: They provide functions to read one or a set of words, one or a set of long words, one or a set of reals. On the first glance, this might seem more convenient and it is as long as it can be applied to PLC memory areas containing only elements of the same type and size. But when you have to deal with data of mixed type and size, you would have to use another call to daveReadBytes() each time the type or size differs from the former. And each call contributes the overhead of the protocol and the response time of the PLC. Other libraries provide a way to read multiple items with a single call. So does Libnodave. You could also use it to retrieve data located on different boundaries. But this is limited to 20 items by the PLC. And it introduces some overhead as an address has to be transmitted for each item in the request. Use read multiple items to access data from different DBs or other memory areas when the combined results will fit in a single response.

When you want to read | do | remark
--- | --- | ---
DB20.DBD0..DBD20 | read 24 bytes starting at DBB0
DB20.DBD0..DBD8 and DBD20 | read 24 bytes starting at DBB0 | just do not evaluate bytes 11 to 19 of result.
DB20.DBD0..DBD8 and DBD120 | either read 124 bytes starting at DBB0 | just do not evaluate bytes 11 to 119 of result.
| or use multiple read on: item1:DB20.DBD0..DBD8, item2:DB20.DBD120 | you have to deal with the result set.
DB20.DBD0..DBD8 and DB21.DBD120 | use multiple read on: item1:DB20.DBD0..DBD8, item2:DB21.DBD120 | this is the only way to read from different DBs with a single request/reponse.
DB20.DBD0..DBD118 and DB21.DBD4..DBD80 | use two calls to daveReadBytes | this is the only way if the two combined results will not fit into a single PDU.