summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fec.c19
-rw-r--r--mcast_image.h6
-rw-r--r--recv_image.c442
-rw-r--r--serve_image.c114
4 files changed, 346 insertions, 235 deletions
diff --git a/fec.c b/fec.c
index e374dfe..09e8453 100644
--- a/fec.c
+++ b/fec.c
@@ -742,6 +742,25 @@ fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
index, code->n - 1 );
}
+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz)
+{
+ int i, k = code->k ;
+ gf *p ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (index < k)
+ bcopy(src + (index * sz), fec, sz*sizeof(gf) ) ;
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index*k] );
+ bzero(fec, sz*sizeof(gf));
+ for (i = 0; i < k ; i++)
+ addmul(fec, src + (i * sz), p[i], sz ) ;
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n",
+ index, code->n - 1 );
+}
/*
* shuffle move src packets in their position
*/
diff --git a/mcast_image.h b/mcast_image.h
index 26c675e..8ca2102 100644
--- a/mcast_image.h
+++ b/mcast_image.h
@@ -9,6 +9,7 @@ struct image_pkt_hdr {
uint32_t blocksize;
uint32_t block_crc;
uint32_t block_nr;
+ uint32_t pkt_sequence;
uint16_t pkt_nr;
uint16_t nr_pkts;
uint32_t thislen;
@@ -32,9 +33,14 @@ void fec_free(struct fec_parms *p);
* fec - buffer for packet to be generated
* index - index of packet to be generated (0 <= index < n)
* sz - data packet size
+ *
+ * _linear version just takes a pointer to the raw data; no
+ * mucking about with packet pointers.
*/
void fec_encode(struct fec_parms *code, unsigned char *src[],
unsigned char *fec, int index, int sz);
+void fec_encode_linear(struct fec_parms *code, unsigned char *src,
+ unsigned char *fec, int index, int sz);
/* data - array of (k) pointers to data packets, in arbitrary order (see i)
* i - indices of (data) packets
diff --git a/recv_image.c b/recv_image.c
index f9705f6..d361e67 100644
--- a/recv_image.c
+++ b/recv_image.c
@@ -14,12 +14,23 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
#include "crc32.h"
#include "mtd/mtd-user.h"
#include "mcast_image.h"
#define min(x,y) ( (x)>(y)?(y):(x) )
+#define WBUF_SIZE 2048
+struct eraseblock {
+ uint32_t flash_offset;
+ unsigned char wbuf[WBUF_SIZE];
+ int wbuf_ofs;
+ int nr_pkts;
+ int *pkt_indices;
+ uint32_t crc;
+};
+
int main(int argc, char **argv)
{
struct addrinfo *ai;
@@ -30,23 +41,22 @@ int main(int argc, char **argv)
size_t len;
int flfd;
struct mtd_info_user meminfo;
- unsigned char *eb_buf;
- unsigned char *blockmap = NULL;
+ unsigned char *eb_buf, *decode_buf, **src_pkts;
int nr_blocks = 0;
- int *pkt_indices;
- unsigned char **pkts;
- int nr_pkts = 0;
int pkts_per_block;
int block_nr = -1;
uint32_t image_crc;
- uint32_t blocks_received = 0;
+ int total_pkts = 0;
loff_t mtdoffset = 0;
- int *stats;
int badcrcs = 0;
int duplicates = 0;
int file_mode = 0;
struct fec_parms *fec;
int i;
+ struct eraseblock *eraseblocks = NULL;
+ uint32_t start_seq;
+ struct timeval start, now;
+ unsigned long fec_time = 0, flash_time = 0, crc_time = 0;
if (argc != 4) {
fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
@@ -69,7 +79,7 @@ int main(int argc, char **argv)
}
if (flfd == -1) {
/* Try again, as if it's a file */
- flfd = open(argv[3], O_CREAT|O_TRUNC|O_WRONLY, 0644);
+ flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
if (flfd < 0) {
perror("open");
exit(1);
@@ -83,31 +93,16 @@ int main(int argc, char **argv)
pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
eb_buf = malloc(pkts_per_block * PKT_SIZE);
- if (!eb_buf) {
+ decode_buf = malloc(pkts_per_block * PKT_SIZE);
+ if (!eb_buf && !decode_buf) {
fprintf(stderr, "No memory for eraseblock buffer\n");
exit(1);
}
-
- pkt_indices = malloc(sizeof(int) * pkts_per_block);
- if (!pkt_indices) {
- fprintf(stderr, "No memory for packet indices\n");
+ src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
+ if (!src_pkts) {
+ fprintf(stderr, "No memory for decode packet pointers\n");
exit(1);
}
- memset(pkt_indices, 0, sizeof(int) * pkts_per_block);
-
- pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
- if (!pkts) {
- fprintf(stderr, "No memory for packet pointers\n");
- exit(1);
- }
- for (i=0; i<pkts_per_block; i++) {
- pkts[i] = malloc(sizeof(struct image_pkt_hdr) + PKT_SIZE);
- if (!pkts[i]) {
- printf("No memory for packets\n");
- exit(1);
- }
- pkts[i] += sizeof(struct image_pkt_hdr);
- }
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
@@ -159,155 +154,263 @@ int main(int argc, char **argv)
exit(1);
while (1) {
- struct image_pkt *thispkt;
+ struct image_pkt thispkt;
- if (nr_pkts < pkts_per_block)
- thispkt = (void *)(pkts[nr_pkts] - sizeof(struct image_pkt_hdr));
- else
- thispkt = (void *)(pkts[0] - sizeof(struct image_pkt_hdr));
-
- len = read(sock, thispkt, sizeof(*thispkt));
+ len = read(sock, &thispkt, sizeof(thispkt));
if (len < 0) {
perror("read socket");
break;
}
- if (len < sizeof(*thispkt)) {
+ if (len < sizeof(thispkt)) {
fprintf(stderr, "Wrong length %d bytes (expected %d)\n",
- len, sizeof(*thispkt));
+ len, sizeof(thispkt));
continue;
}
- if (!blockmap) {
- image_crc = thispkt->hdr.totcrc;
- if (meminfo.erasesize != ntohl(thispkt->hdr.blocksize)) {
+ if (!eraseblocks) {
+ image_crc = thispkt.hdr.totcrc;
+ start_seq = ntohl(thispkt.hdr.pkt_sequence);
+
+ if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
- ntohl(thispkt->hdr.blocksize), meminfo.erasesize);
+ ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
exit(1);
}
- nr_blocks = ntohl(thispkt->hdr.nr_blocks);
- nr_pkts = 0;
+ nr_blocks = ntohl(thispkt.hdr.nr_blocks);
- fec = fec_new(pkts_per_block, ntohs(thispkt->hdr.nr_pkts));
+ fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
- blockmap = malloc(nr_blocks);
- if (!blockmap) {
+ eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
+ if (!eraseblocks) {
fprintf(stderr, "No memory for block map\n");
exit(1);
}
- memset(blockmap, 0, nr_blocks);
- stats = malloc(sizeof(int) * (ntohs(thispkt->hdr.nr_pkts) + 1));
- if (!stats) {
- fprintf(stderr, "No memory for statistics\n");
- exit(1);
- }
- memset(stats, 0, sizeof(int) * (ntohs(thispkt->hdr.nr_pkts) + 1));
- }
- if (image_crc != thispkt->hdr.totcrc) {
- fprintf(stderr, "Image CRC changed from 0x%x to 0x%x. Aborting\n",
- ntohl(image_crc), ntohl(thispkt->hdr.totcrc));
- exit(1);
- }
- if (ntohl(thispkt->hdr.block_nr) != block_nr) {
- /* Hm, new block */
- if (block_nr != -1) {
- if (!blockmap[block_nr]) {
- printf("Lost image block %08x with only %d/%d (%d) packets\n",
- block_nr * meminfo.erasesize, nr_pkts, pkts_per_block,
- ntohs(thispkt->hdr.nr_pkts));
+ for (i = 0; i < nr_blocks; i++) {
+ eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
+ if (!eraseblocks[i].pkt_indices) {
+ fprintf(stderr, "Failed to allocate packet indices\n");
+ exit(1);
}
- if (blockmap[block_nr] < 2) {
- stats[nr_pkts]++;
- if (blockmap[block_nr]) {
- if (file_mode)
- printf(" with %d/%d (%d) packets\n",
- nr_pkts, pkts_per_block,
- ntohs(thispkt->hdr.nr_pkts));
- blockmap[block_nr] = 2;
+ eraseblocks[i].nr_pkts = 0;
+ if (!file_mode) {
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
}
+#if 1 /* Deliberately use bad blocks... test write failures */
+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+ mtdoffset += meminfo.erasesize;
+ }
+#endif
}
+ eraseblocks[i].flash_offset = mtdoffset;
+ mtdoffset += meminfo.erasesize;
+ eraseblocks[i].wbuf_ofs = 0;
}
- /* Put this packet first */
- if (nr_pkts != 0 && nr_pkts < pkts_per_block) {
- unsigned char *tmp = pkts[0];
- pkts[0] = pkts[nr_pkts];
- pkts[nr_pkts] = tmp;
-
- }
- nr_pkts = 0;
-
- block_nr = ntohl(thispkt->hdr.block_nr);
-
- if (block_nr > nr_blocks) {
- fprintf(stderr, "Erroneous block_nr %d (> %d)\n",
- block_nr, nr_blocks);
- exit(1);
- }
- if (blockmap[block_nr]) {
- printf("Discard chunk at 0x%08x for already-flashed eraseblock (%d to go)\n",
- block_nr * meminfo.erasesize, nr_blocks - blocks_received);
- continue;
- }
+ gettimeofday(&start, NULL);
}
- if (nr_pkts >= pkts_per_block) {
- /* We have a parity block but we didn't need it */
- nr_pkts++;
- continue;
+ if (image_crc != thispkt.hdr.totcrc) {
+ fprintf(stderr, "Image CRC changed from 0x%x to 0x%x. Aborting\n",
+ ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
+ exit(1);
}
- if (blockmap[block_nr])
- continue;
- for (i=0; i < nr_pkts; i++) {
- if (pkt_indices[i] == ntohs(thispkt->hdr.pkt_nr)) {
- printf("Discarding duplicate packet at %08x pkt %d\n",
- block_nr * meminfo.erasesize, pkt_indices[i]);
+ block_nr = ntohl(thispkt.hdr.block_nr);
+ if (block_nr >= nr_blocks) {
+ fprintf(stderr, "Erroneous block_nr %d (> %d)\n",
+ block_nr, nr_blocks);
+ exit(1);
+ }
+ for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
+ if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
+// printf("Discarding duplicate packet at %08x pkt %d\n",
+// block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
duplicates++;
break;
}
- } /* And if we broke out, skip the packet... */
- if (i < nr_pkts)
+ }
+ if (i < eraseblocks[block_nr].nr_pkts)
continue;
- if (crc32(-1, thispkt->data, PKT_SIZE) != ntohl(thispkt->hdr.thiscrc)) {
+ if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
+ /* We have a block which we didn't really need */
+ eraseblocks[block_nr].nr_pkts++;
+ continue;
+ }
+
+ if (crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
printf("Discard %08x pkt %d with bad CRC (%08x not %08x)\n",
- block_nr * meminfo.erasesize, ntohs(thispkt->hdr.pkt_nr),
- crc32(-1, thispkt->data, PKT_SIZE),
- ntohl(thispkt->hdr.thiscrc));
+ block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
+ crc32(-1, thispkt.data, PKT_SIZE),
+ ntohl(thispkt.hdr.thiscrc));
badcrcs++;
continue;
}
+ pkt_again:
+ eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
+ ntohs(thispkt.hdr.pkt_nr);
+ total_pkts++;
+ if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
+ uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq - 1;
+ long time_msec;
+ gettimeofday(&now, NULL);
- pkt_indices[nr_pkts] = ntohs(thispkt->hdr.pkt_nr);
- nr_pkts++;
+ time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
+ (now.tv_sec - start.tv_sec) * 1000;
- if (nr_pkts == pkts_per_block) {
+ printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dups ",
+ total_pkts, nr_blocks * pkts_per_block,
+ total_pkts * 100 / nr_blocks / pkts_per_block,
+ time_msec / 1000,
+ total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
+ pkts_sent - total_pkts - duplicates,
+ (pkts_sent - total_pkts - duplicates) * 100 / pkts_sent,
+ duplicates);
+ }
- if (fec_decode(fec, pkts, pkt_indices, PKT_SIZE)) {
- /* Eep. This cannot happen */
- printf("The world is broken. fec_decode() returned error\n");
- exit(1);
+ if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
+ /* New packet doesn't full the wbuf */
+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+ thispkt.data, PKT_SIZE);
+ eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
+ } else {
+ int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
+ ssize_t wrotelen;
+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+ thispkt.data, fits);
+ wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
+ eraseblocks[block_nr].flash_offset);
+
+ if (wrotelen < WBUF_SIZE) {
+ if (wrotelen < 0)
+ perror("packet write");
+ else
+ fprintf(stderr, "short write of packet wbuf\n");
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+ /* FIXME: Perhaps we should store pkt crcs and try
+ to recover data from the offending eraseblock */
+ erase.start = eraseblocks[block_nr].flash_offset;
+ erase.start -= eraseblocks[block_nr].nr_pkts * PKT_SIZE / WBUF_SIZE * WBUF_SIZE;
+ erase.length = meminfo.erasesize;
+
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ exit(1);
+ }
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+ mtdoffset += meminfo.erasesize;
+ }
+ eraseblocks[block_nr].flash_offset = mtdoffset;
+ total_pkts -= eraseblocks[block_nr].nr_pkts;
+ eraseblocks[block_nr].nr_pkts = 0;
+ goto pkt_again;
+ }
+ else /* Usually nothing we can do in file mode */
+ exit(1);
}
- blockmap[block_nr] = 1;
- blocks_received++;
-
- /* Put data into order in eb_buf */
- for (i=0; i < pkts_per_block; i++)
- memcpy(eb_buf + (i * PKT_SIZE), pkts[i], PKT_SIZE);
-
- if (crc32(-1, eb_buf, meminfo.erasesize) != ntohl(thispkt->hdr.block_crc)) {
- printf("FEC error. CRC %08x != %08x\n",
- crc32(-1, eb_buf, meminfo.erasesize),
- ntohl(thispkt->hdr.block_crc));
- *(int *)0 = 0;
+ eraseblocks[block_nr].flash_offset += WBUF_SIZE;
+ /* Copy the remainder into the wbuf */
+ memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
+ eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
+ }
+
+ if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
+ eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
+
+ if (total_pkts == nr_blocks * pkts_per_block)
+ break;
+ }
+ }
+ close(sock);
+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+ ssize_t rwlen;
+
+ eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
+ rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+
+ if (rwlen < 0) {
+ perror("read");
+ /* Argh. Perhaps we could go back and try again, but if the flash is
+ going to fail to read back what we write to it, and the whole point
+ in this program is to write to it, what's the point? */
+ fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
+ exit(1);
+ }
+
+ memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
+ eraseblocks[block_nr].wbuf_ofs);
+
+ for (i=0; i < pkts_per_block; i++)
+ src_pkts[i] = &eb_buf[i * PKT_SIZE];
+
+ gettimeofday(&start, NULL);
+ if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
+ /* Eep. This cannot happen */
+ printf("The world is broken. fec_decode() returned error\n");
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ fec_time += (now.tv_usec - start.tv_usec) / 1000;
+ fec_time += (now.tv_sec - start.tv_sec) * 1000;
+
+ for (i=0; i < pkts_per_block; i++)
+ memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
+
+ /* Paranoia */
+ gettimeofday(&start, NULL);
+ if (crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
+ printf("CRC mismatch: want %08x got %08x\n",
+ eraseblocks[block_nr].crc,
+ crc32(-1, decode_buf, meminfo.erasesize));
+ }
+ gettimeofday(&now, NULL);
+ crc_time += (now.tv_usec - start.tv_usec) / 1000;
+ crc_time += (now.tv_sec - start.tv_sec) * 1000;
+ start = now;
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+
+ erase.start = eraseblocks[block_nr].flash_offset;
+ erase.length = meminfo.erasesize;
+
+ printf("Erasing block at %08x...", erase.start);
+
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ /* This block has dirty data on it. If the erase failed, we're screwed */
+ fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
exit(1);
}
- if (file_mode) {
- printf("Received image block %08x (%d/%d)",
- block_nr * meminfo.erasesize,
- blocks_received, nr_blocks);
- pwrite(flfd, eb_buf, meminfo.erasesize, block_nr * meminfo.erasesize);
- } else {
- ssize_t wrotelen;
- again:
+ }
+ write_again:
+ rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+ if (rwlen < meminfo.erasesize) {
+ if (rwlen < 0) {
+ perror("decoded data write");
+ } else
+ fprintf(stderr, "short write of decoded data\n");
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+ erase.start = eraseblocks[block_nr].flash_offset;
+ erase.length = meminfo.erasesize;
+
+ printf("Erasing failed block at %08x\n",
+ eraseblocks[block_nr].flash_offset);
+
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ exit(1);
+ }
if (mtdoffset >= meminfo.size) {
fprintf(stderr, "Run out of space on flash\n");
exit(1);
@@ -316,54 +419,25 @@ int main(int argc, char **argv)
printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
mtdoffset += meminfo.erasesize;
}
- wrotelen = pwrite(flfd, eb_buf, meminfo.erasesize, mtdoffset);
- if (wrotelen != meminfo.erasesize) {
- struct erase_info_user erase;
-
- if (wrotelen < 0)
- perror("flash write");
- else
- fprintf(stderr, "Short write to flash at %08x: %zd bytes\n",
- (uint32_t)mtdoffset, wrotelen);
-
- erase.start = mtdoffset;
- erase.length = meminfo.erasesize;
-
- if (ioctl(flfd, MEMERASE, erase)) {
- perror("MEMERASE");
- exit(1);
- }
- /* skip it */
- // ioctl(flfd, MEMSETBADBLOCK, &mtdoffset);
- mtdoffset += meminfo.erasesize;
- goto again;
- }
- printf("Wrote image block %08x (%d/%d) to flash offset %08x\n",
- block_nr * meminfo.erasesize,
- blocks_received, nr_blocks,
- (uint32_t)mtdoffset);
- mtdoffset += meminfo.erasesize;
- }
- if (!(blocks_received%100) || blocks_received == nr_blocks) {
- int i, printed = 0;
- printf("\n");
- for (i=0; i <= ntohs(thispkt->hdr.nr_pkts); i++) {
- if (printed || stats[i]) {
- printf("Number of blocks with %d packets received: %d\n",
- i, stats[i]);
- printed = 1;
- }
- }
- printf("Bad CRC: %d\n", badcrcs);
- printf("Duplicate: %d\n", duplicates);
+ printf("Will try again at %08lx...", (long)mtdoffset);
+ eraseblocks[block_nr].flash_offset = mtdoffset;
+ goto write_again;
}
- if (blocks_received == nr_blocks) {
- printf("Got all %08x bytes of image. Bye!\n",
- nr_blocks * meminfo.erasesize);
- exit(0);
- }
+ else /* Usually nothing we can do in file mode */
+ exit(1);
}
+ gettimeofday(&now, NULL);
+ flash_time += (now.tv_usec - start.tv_usec) / 1000;
+ flash_time += (now.tv_sec - start.tv_sec) * 1000;
+
+ printf("wrote image block %08x (%d pkts)\n",
+ block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
}
- close(sock);
+ close(flfd);
+ printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
+ printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
+ printf("flash IO %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
+
+ return 0;
}
diff --git a/serve_image.c b/serve_image.c
index 57d2bd9..30ceaeb 100644
--- a/serve_image.c
+++ b/serve_image.c
@@ -36,36 +36,26 @@ int main(int argc, char **argv)
struct stat st;
int writeerrors = 0;
uint32_t erasesize;
- unsigned char *image, *blockptr;
+ unsigned char *image, *blockptr = NULL;
uint32_t block_nr, pkt_nr;
int nr_blocks;
struct timeval then, now, nextpkt;
long time_msecs;
- int pkts_extra = 6;
int pkts_per_block;
struct fec_parms *fec;
unsigned char *last_block;
uint32_t *block_crcs;
- int crcs_checked = 0;
long tosleep;
+ uint32_t sequence = 0;
- if (argc == 7) {
- tx_rate = atol(argv[6]) * 1024;
+ if (argc == 6) {
+ tx_rate = atol(argv[5]) * 1024;
if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
exit(1);
}
- argc = 6;
- }
- if (argc == 6) {
- pkts_extra = atol(argv[5]);
- if (pkts_extra < 0 || pkts_extra > 200) {
- fprintf(stderr, "Bogus redundancy %d packets\n", pkts_extra);
- exit(1);
- }
argc = 5;
}
-
if (argc != 5) {
fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<redundancy>] [<tx_rate>]\n",
(strrchr(argv[0], '/')?:argv[0]-1)+1);
@@ -90,7 +80,7 @@ int main(int argc, char **argv)
exit(1);
}
- fec = fec_new(pkts_per_block, pkts_per_block + pkts_extra);
+ fec = fec_new(pkts_per_block, pkts_per_block * 2);
if (!fec) {
fprintf(stderr, "Error initialising FEC\n");
exit(1);
@@ -162,16 +152,23 @@ int main(int argc, char **argv)
pktbuf.hdr.nr_blocks = htonl(nr_blocks);
pktbuf.hdr.blocksize = htonl(erasesize);
pktbuf.hdr.thislen = htonl(PKT_SIZE);
- pktbuf.hdr.nr_pkts = htons(pkts_per_block + pkts_extra);
+ pktbuf.hdr.nr_pkts = htons(pkts_per_block * 2);
printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
-
- again:
- printf("Image size %ld KiB (%08lx). %d redundant packets per block (%d total)\n"
- "Data to send %d KiB. Estimated transmit time: %ds\n",
- (long)st.st_size / 1024, (long) st.st_size, pkts_extra, pkts_extra+pkts_per_block,
- nr_blocks * PKT_SIZE * (pkts_per_block+pkts_extra) / 1024,
- nr_blocks * (pkts_per_block+pkts_extra) * pkt_delay / 1000000);
+ printf("Checking block CRCs....");
+ fflush(stdout);
+ for (block_nr=0; block_nr < nr_blocks; block_nr++) {
+ printf("\rChecking block CRCS.... %d/%d",
+ block_nr + 1, nr_blocks);
+ fflush(stdout);
+ block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize);
+ }
+
+ printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
+ "Estimated transmit time per cycle: %ds\n",
+ (long)st.st_size / 1024, (long) st.st_size,
+ nr_blocks, pkts_per_block,
+ nr_blocks * pkts_per_block * pkt_delay / 1000000);
gettimeofday(&then, NULL);
nextpkt = then;
@@ -179,47 +176,69 @@ int main(int argc, char **argv)
srand((unsigned)then.tv_usec);
printf("Random seed %u\n", (unsigned)then.tv_usec);
#endif
- blockptr = image;
+ while (1) for (pkt_nr=0; pkt_nr < pkts_per_block * 2; pkt_nr++) {
+
+ if (blockptr && pkt_nr == 0) {
+ unsigned long amt_sent = pkts_per_block * nr_blocks * sizeof(pktbuf) * 2;
+ gettimeofday(&now, NULL);
- for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+ time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+ printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
+ amt_sent / 1024, time_msecs,
+ amt_sent / 1024 * 1000 / time_msecs);
+ then = now;
+ }
+
+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+
+ int actualpkt;
- for (pkt_nr=0; pkt_nr < pkts_per_block + pkts_extra; pkt_nr++) {
+ /* Calculating the redundant FEC blocks is expensive;
+ the first $pkts_per_block are cheap enough though
+ because they're just copies. So alternate between
+ simple and complex stuff, so that we don't start
+ to choke and fail to keep up with the expected
+ bitrate in the second half of the sequence */
+ if (block_nr & 1)
+ actualpkt = pkt_nr;
+ else if (pkt_nr >= pkts_per_block)
+ actualpkt = pkt_nr - pkts_per_block;
+ else
+ actualpkt = pkt_nr + pkts_per_block;
blockptr = image + (erasesize * block_nr);
if (block_nr == nr_blocks - 1)
blockptr = last_block;
- /* Calculate the block CRCs first time around */
- if (block_nr >= crcs_checked) {
- block_crcs[block_nr] = crc32(-1, blockptr, erasesize);
- crcs_checked = block_nr + 1;
- }
+ fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
pktbuf.hdr.block_nr = htonl(block_nr);
+ pktbuf.hdr.pkt_nr = htons(actualpkt);
+ pktbuf.hdr.pkt_sequence = htonl(sequence++);
- fec_encode_linear(fec, blockptr, pktbuf.data, pkt_nr, PKT_SIZE);
-
printf("\rSending data block %08x packet %3d/%d",
- block_nr * erasesize, pkt_nr, pkts_per_block + pkts_extra);
+ block_nr * erasesize,
+ pkt_nr, pkts_per_block * 2);
+
+ if (pkt_nr && !block_nr) {
+ unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
- if (block_nr && !pkt_nr) {
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
printf(" (%ld KiB/s) ",
- (block_nr * sizeof(pktbuf) * (pkts_per_block+pkts_extra))
- / 1024 * 1000 / time_msecs);
+ amt_sent / 1024 * 1000 / time_msecs);
}
fflush(stdout);
- pktbuf.hdr.pkt_nr = htons(pkt_nr);
- pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
#ifdef RANDOMDROP
if ((rand() % 1000) < 20) {
- printf("\nDropping packet %d\n", pkt_nr+1);
+ printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
continue;
}
#endif
@@ -251,9 +270,10 @@ int main(int argc, char **argv)
}
/* If the time for the next packet has already
- passed, then we've lost time. Adjust our expected
- timings accordingly. */
- if (now.tv_usec > (now.tv_usec +
+ passed (by some margin), then we've lost time
+ Adjust our expected timings accordingly. If
+ we're only a little way behind, don't slip yet */
+ if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
1000000 * (nextpkt.tv_sec - now.tv_sec))) {
nextpkt = now;
}
@@ -272,14 +292,6 @@ int main(int argc, char **argv)
}
}
- gettimeofday(&now, NULL);
-
- time_msecs = (now.tv_sec - then.tv_sec) * 1000;
- time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
- printf("\n%d KiB sent in %ldms (%ld KiB/s)\n",
- nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024, time_msecs,
- nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024 * 1000 / time_msecs);
-
munmap(image, st.st_size);
close(rfd);
close(sock);