#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>

#include "rk27load.h"
#include "common.h"
#include "scramble.h"
#include "checksum.h"
#include "stage3_upload.h"

int upload_stage3_code(libusb_device_handle *hdev, char *fn_stage3)
{
    FILE *f;
    uint32_t codesize;
    uint32_t remain;
    uint8_t *code;
    uint16_t send_size = 0x200;
    uint32_t i = 0;
    int ret, transfered;

    if ((f = fopen(fn_stage3, "rb")) == NULL)
    {
        fprintf(stderr, "[error]: Could not open file \"%s\"\n", fn_stage3);
        return -31;
    }

    codesize = filesize(f);

    fprintf(stderr, "[stage3]: Loading user code (%d bytes)... ", codesize);

    /* allocate buffer */
    code = (uint8_t *) malloc(codesize + 0x204);
    if (code == NULL)
    {
        fprintf(stderr, "\n[error]: Out of memory\n");
        fclose(f);
        return -32;
    }

    memset(code, 0, codesize + 0x204);
    /* read usercode into buffer */
    if (fread(&code[4], 1, codesize, f) != codesize)
    {
        fprintf(stderr, "\n[error]: I/O error\n");
        fclose(f);
        free(code);
        return -33;
    }
    fprintf(stderr, "done\n");

    fclose(f);

    /* put code size at the first 4 bytes */
    codesize += 4;
    code[0] = codesize & 0xff;
    code[1] = (codesize >> 8) & 0xff;
    code[2] = (codesize >> 16) & 0xff;
    code[3] = (codesize >> 24) & 0xff;

    fprintf(stderr, "[stage3]: Uploading user code (%d bytes)... ", codesize);

    remain = codesize;

    while (remain > 0)
    {
        if (remain < 0x200)
            send_size = remain;

        ret = libusb_bulk_transfer(hdev,                           /* handle */
                                   1,                              /* EP */
                                   &code[i * 0x200],               /* data */
                                   send_size,                      /* length */
                                   &transfered,                    /* xfered */
                                   USB_TIMEOUT                     /* timeout */
                                  );

        if (ret != LIBUSB_SUCCESS)
        {
            fprintf(stderr, "\n[error]: Bulk transfer error (%d, %d)\n", ret, i);
            free(code);
            return -34;
        }

        remain -= send_size;
        i++;
    }

    fprintf(stderr,"done (sent %d blocks)\n", i);
    return 0;
}

