summaryrefslogtreecommitdiff
path: root/util/upload.c
blob: 5eb5d81e7e1cb556b9ecc21fed76785aa38128e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include "tty.h"

static const uint8_t magic[] =
    {0x2D, 0xC0, 0x3B, 0x5F, 0xEA, 0xE3, 0x1A, 0x3A, 0x83, 0x11, 0x6A, 0x33, 0x98, 0x46, 0x1C, 0x47};

#define ACK         0x05
#define NACK        0x0A
#define BLK_SIZE    256

void usage(char *p) {
    fprintf(stderr, "Usage: %s <tty> <firmware>\n", p);
    exit(1);
}

uint32_t crc32x(unsigned char *buf, size_t len, uint32_t crc) {
    int i;

    crc = ~crc;
    while (len--) {
        crc ^= *buf++;
        for (i=0; i<8; i++) {
            uint32_t t = ~((crc & 1) - 1);
            crc = (crc >> 1) ^ (0xEDB88320 & t);
        }
    }

    return ~crc;
}

void set_buffer(uint32_t addr, uint8_t *buf) {
    uint32_t crc32;

    buf[0] = addr >> 24;
    buf[1] = addr >> 16;
    buf[2] = addr >> 8;
    buf[3] = addr;
    crc32 = crc32x(buf, BLK_SIZE + sizeof(uint32_t), 0xffffffff);
    buf[BLK_SIZE + 4] = crc32 >> 24;
    buf[BLK_SIZE + 5] = crc32 >> 16;
    buf[BLK_SIZE + 6] = crc32 >> 8;
    buf[BLK_SIZE + 7] = crc32;
}

static void _write(int fd, const uint8_t *buf, size_t size) {
    int rv = 0;

    do {
        rv += write(fd, buf + rv, size - rv);
    } while (rv != size);
}

int main(int argc, char *argv[]) {
    int tty_fd, fw_fd;
    uint8_t buf[BLK_SIZE + 2 * sizeof(uint32_t)];
    uint32_t addr;
    int rv;

    if (argc != 3) {
        usage(argv[0]);
    }

    tty_fd = tty_open(argv[1]);
    if (tty_fd < 0) {
        fprintf(stderr, "TTY OPEN ERROR %i: %s\n", errno, strerror(errno));
        return 1;
    }

    fw_fd = open(argv[2], O_RDONLY);
    if (fw_fd < 0) {
        fprintf(stderr, "FW OPEN ERROR %i: %s\n", errno, strerror(errno));
        return 1;
    }

    while ((rv = read(tty_fd, buf, sizeof(buf))));

    _write(tty_fd, magic, sizeof(magic));
    *buf = NACK;
    read(tty_fd, buf, 1);
    if (*buf != ACK) {
        fprintf(stderr, "CONNECT ERROR: %x\n", *buf);
        return 1;
    }
    printf("CONNECTED\n");

    addr = 0;
    memset(buf, 0xff, sizeof(buf));
    do {
        rv = read(fw_fd, buf + sizeof(uint32_t), BLK_SIZE);
        if (rv < 0) {
            fprintf(stderr, "FW READ ERROR %i: %s\n", errno, strerror(errno));
            return 1;
        }
        if (rv == 0) {
            addr = -1;
        }

        set_buffer(addr, buf);
        do {
            _write(tty_fd, buf, sizeof(buf));
            *buf = NACK;
            read(tty_fd, buf, 1);
            if (*buf == NACK) {
                fprintf(stderr, "NACK...\n");
            }
        } while (*buf != ACK);
        addr += BLK_SIZE;
        memset(buf, 0xff, sizeof(buf));
    } while (rv);

    close(tty_fd);
    close(fw_fd);

    return 0;
}