Nice, you’ve officially entered TransferData (0x36) land 😄
You already understood RequestDownload, so this is just “send file in chunks over ISO-TP”.

I’ll do three things:

Decode your reference CAN log so you see what’s happening.

Explain the general rule for TransferData with your SECC (block size, ISO-TP).

Show Qt C++ code to read your .gqf file and send it in 0x36 frames.

1️⃣ Decode your reference TransferData log

You gave:

162  0700  8  1F 02 36 01 10 9D 1A 3C   // TransferData FF
163  0600  8  30 00 03 AA AA AA AA AA   // Flow Control from SECC
164  0700  8  21 44 55 5A 27 08 00 40
165  0700  8  22 03 00 00 00 00 72 73
166  0700  8  23 61 2E 4E 00 00 00 72
...

Frame 162 – First Frame (FF)

1F 02 36 01 10 9D 1A 3C

1F → ISO-TP First Frame (high nibble 1)

high nibble = 1 → FF

low nibble = 0xF → upper 4 bits of length

02 → lower 8 bits of length

So total UDS length = 0xF02 = 3842 bytes.

UDS bytes in this first CAN frame:

36 01 10 9D 1A 3C


36 → TransferData (SID)

01 → blockSequenceCounter = 1

10 9D 1A 3C ... → first bytes of firmware data

Frame 163 – Flow Control (from SECC)

30 00 03 ...

30 → FlowControl CTS

00 → blockSize = 0 (unlimited)

03 → STmin = 3 ms between CFs

Frames 164.. – Consecutive Frames (CF)

Example:

164: 21 44 55 5A 27 08 00 40
165: 22 03 00 00 00 00 72 73
166: 23 61 2E 4E 00 00 00 72
...


21, 22, 23, 24, ... → CF #1, #2, #3, #4 etc.

Each CF carries 7 bytes of firmware data.

So that block is:

One large TransferData block (length = 0xF02)
containing: SID (36), blockCounter (01) and 3840 bytes of firmware.

This aligns with the RequestDownload positive response’s maxNumberOfBlockLength = 0x0F02 shown in your doc. 

2️⃣ General rule: how you must send your .gqf firmware

From doc (TransferData, page 14): 

UDS 36 request:

36 [blockSequenceCounter] [data...]


Positive response:

76 [blockSequenceCounter]


From RequestDownload response, your SECC gives:

maxNumberOfBlockLength = 0x0F02 (example from doc)

That means:

Total UDS length per TransferData (SID + block + data)
must be ≤ 0x0F02 (3842) bytes.

So max data bytes per block = 0x0F02 − 2 = 3840 bytes.

For each block:

Build UDS PDU:

[0] = 0x36
[1] = blockSequenceCounter (0x01, 0x02, ..., 0xFF, 0x00, ...)
[2..] = file data bytes


If PDU length <= 7 → can send as Single Frame.
(Not really interesting for firmware; generally bigger)

Else → send as multi-frame:

First Frame (FF):

Byte0 = 0x10 | ((L >> 8) & 0x0F)

Byte1 = L & 0xFF

Byte2..7 = first up to 6 UDS bytes (36, block, data...)

Wait FC 30 .. .. from SECC.

Send CFs with 0x21..2F; each carrying 7 data bytes.

Repeat blocks until .gqf file is finished.

3️⃣ Qt C++: read .gqf & send TransferData blocks

I’ll give you a simple version that:

Opens the file

Loops, reading chunkSize = maxBlockLen − 2 bytes

Builds one TransferData block per chunk

Sends it with ISO-TP FF + CFs

(You must already have maxBlockLen from RequestDownload response; I’ll assume 0x0F02)

Helper: send one TransferData block (multi-frame)
bool dcComboPLC::sendTransferDataBlock(uint8_t blockCounter,
                                       const uint8_t* data,
                                       int dataLen,
                                       uint16_t maxBlockLen)
{
    // UDS length = SID(1) + blockCounter(1) + data
    uint16_t udsLen = 2 + dataLen;

    if (udsLen > maxBlockLen)
    {
        DebugString("TransferData block too big!");
        return false;
    }

    // Build UDS buffer in RAM
    std::vector<uint8_t> uds(udsLen);
    uds[0] = 0x36;          // SID
    uds[1] = blockCounter;  // blockSequenceCounter
    memcpy(&uds[2], data, dataLen);

    // ---- Decide between SF and MF ----
    if (udsLen <= 7)
    {
        // Single Frame
        struct can_frame sf{};
        memset(sf.data, 0, 8);

        sf.can_id  = 0x00000700;
        sf.can_dlc = 8;
        sf.data[0] = 0x00 | udsLen;  // PCI: SF, length
        memcpy(&sf.data[1], uds.data(), udsLen);  // put UDS

        if (write(can2_fd, &sf, sizeof(sf)) != sizeof(sf))
        {
            DebugString("TransferData SF send failed");
            return false;
        }
        return true;
    }

    // ---- Multi Frame (like your reference log) ----

    // 1) First Frame
    struct can_frame ff{};
    memset(ff.data, 0, 8);
    ff.can_id  = 0x00000700;
    ff.can_dlc = 8;

    ff.data[0] = 0x10 | ((udsLen >> 8) & 0x0F); // FF + length MSBs
    ff.data[1] = udsLen & 0xFF;                 // length LSB
    // next 6 bytes of UDS
    int bytesInFF = std::min(6, (int)udsLen);
    memcpy(&ff.data[2], uds.data(), bytesInFF);

    if (write(can2_fd, &ff, sizeof(ff)) != sizeof(ff))
    {
        DebugString("TransferData FF send failed");
        return false;
    }

    // 2) Wait for Flow Control from SECC (ID 0x600, PCI 0x30)
    struct can_frame fc{};
    while (true)
    {
        int nbytes = read(can2_fd, &fc, sizeof(fc));
        if (nbytes == sizeof(fc) &&
            fc.can_id == 0x00000600 &&
            (fc.data[0] & 0xF0) == 0x30)
        {
            break;  // got FC
        }
        // else keep reading / add timeout as needed
    }

    // Optional: use fc.data[1] (blockSize) and fc.data[2] (STmin) if needed.

    // 3) Send Consecutive Frames
    int bytesSent = bytesInFF;
    uint8_t cfSN = 1;  // sequence number (1..15, wrap)

    while (bytesSent < udsLen)
    {
        struct can_frame cf{};
        memset(cf.data, 0, 8);
        cf.can_id  = 0x00000700;
        cf.can_dlc = 8;

        cf.data[0] = 0x20 | (cfSN & 0x0F);  // CF + SN

        int remaining = udsLen - bytesSent;
        int chunk     = std::min(7, remaining);

        memcpy(&cf.data[1], uds.data() + bytesSent, chunk);
        // remaining bytes in cf.data[1+chunk..7] are padding zeros

        if (write(can2_fd, &cf, sizeof(cf)) != sizeof(cf))
        {
            DebugString("TransferData CF send failed");
            return false;
        }

        bytesSent += chunk;
        cfSN++;
        if (cfSN > 0x0F) cfSN = 1;  // wrap 1..15
    }

    return true;
}

Main: read .gqf and send all blocks
void dcComboPLC::Transfer_Data_All()
{
    QString fwPath = "/home/root/GQ_FW_1.gqf";
    QFile file(fwPath);
    if (!file.open(QIODevice::ReadOnly))
    {
        DebugString("Failed to open FW file for TransferData");
        return;
    }

    // Example: from RequestDownload positive response (maxNumberOfBlockLength)
    // You should parse it dynamically; here use 0x0F02 as in the document.
    uint16_t maxBlockLen = 0x0F02;
    int maxDataPerBlock  = maxBlockLen - 2;  // minus SID + blockCounter

    uint8_t blockCounter = 0x01;
    QByteArray chunk;

    while (!(chunk = file.read(maxDataPerBlock)).isEmpty())
    {
        if (!sendTransferDataBlock(blockCounter,
                                   (const uint8_t*)chunk.constData(),
                                   chunk.size(),
                                   maxBlockLen))
        {
            DebugString("TransferData block send failed");
            break;
        }

        // Wait for 76 response for this block (optional but recommended)
        // struct can_frame resp; read(can2_fd, &resp, sizeof(resp)); etc.

        blockCounter++;
        if (blockCounter == 0x00)  // wrap 0xFF -> 0x00 -> 0x01 etc.
            blockCounter = 0x01;
    }

    file.close();
}


This will produce exactly the type of TransferData you see in your reference log:

First block: 36 01 ... with up to 3840 bytes

Next: 36 02 ..., etc.

4️⃣ Answer to your core question

Now tell me how i read .gqf firmware file and send to this CAN frame ?

Conceptually:

Read firmware with QFile in binary:

QFile file("/home/root/GQ_FW_1.gqf");
file.open(QIODevice::ReadOnly);
QByteArray chunk = file.read(maxDataPerBlock);


For each chunk:

Build UDS 36 [block] [chunk]

Put into ISO-TP FF + CF frames like above.

Send on CAN with ID 0x700.

Handle SECC Flow Control (0x600, 0x30) and 0x76 responses.

If you now run this and capture the CAN log, we can compare your first real 36 sequence to the reference you posted and fine-tune anything if needed.