[Cryptech-Commits] [sw/stm32] 03/03: E-Kermit, for file upload goodness

git at cryptech.is git at cryptech.is
Tue Jun 21 02:54:04 UTC 2016


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch ekermit
in repository sw/stm32.

commit 5a0fb1ce24abe38ada705327868a5601b59e8ec4
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Mon Jun 20 22:46:18 2016 -0400

    E-Kermit, for file upload goodness
---
 Makefile                                  |   8 +
 libraries/thirdparty/ekermit/Makefile     |  17 ++
 libraries/thirdparty/ekermit/stm-kermit.c | 434 ++++++++++++++++++++++++++++++
 libraries/thirdparty/ekermit/stm-kermit.h |  42 +++
 projects/ekermit-test/Makefile            |  22 ++
 projects/ekermit-test/ekermit-test.c      | 167 ++++++++++++
 6 files changed, 690 insertions(+)

diff --git a/Makefile b/Makefile
index 1bdb5fa..e41b94d 100644
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@ export RTOS_DIR = $(MBED_DIR)/rtos
 export LIBTFM_DIR = $(LIBS_DIR)/thirdparty/libtfm
 export LIBHAL_DIR = $(LIBS_DIR)/libhal
 export LIBCLI_DIR = $(LIBS_DIR)/libcli
+export EKERMIT_DIR = $(LIBS_DIR)/thirdparty/ekermit
 
 export LIBS = $(MBED_DIR)/libstmf4.a
 
@@ -133,6 +134,12 @@ $(LIBHAL_DIR)/libhal.a: $(LIBTFM_DIR)/libtfm.a
 $(LIBCLI_DIR)/libcli.a:
 	$(MAKE) -C $(LIBCLI_DIR)
 
+$(EKERMIT_DIR)/libekermit.a:
+	$(MAKE) -C $(EKERMIT_DIR)
+
+ekermit-test: $(BOARD_OBJS) $(LIBS) $(EKERMIT_DIR)/libekermit.a
+	$(MAKE) -C projects/ekermit-test
+
 libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_DIR)/libhal.a
 	$(MAKE) -C projects/libhal-test
 
@@ -160,3 +167,4 @@ distclean: clean
 	$(MAKE) -C $(RTOS_DIR) clean
 	$(MAKE) -C $(LIBHAL_DIR) clean
 	$(MAKE) -C $(LIBTFM_DIR) clean
+	$(MAKE) -C $(EKERMIT_DIR) clean
diff --git a/libraries/thirdparty/ekermit/Makefile b/libraries/thirdparty/ekermit/Makefile
new file mode 100644
index 0000000..8dd856f
--- /dev/null
+++ b/libraries/thirdparty/ekermit/Makefile
@@ -0,0 +1,17 @@
+EKERMIT = ../../../../thirdparty/ekermit
+
+vpath %.c $(EKERMIT)
+
+OBJS = kermit.o stm-kermit.o
+
+LIB = libekermit.a
+
+CFLAGS += -I$(EKERMIT) -DSTATIC=static -DRECVONLY -DMINSIZE #-DDEBUG
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+	$(AR) -r $@ $(OBJS)
+
+clean:
+	rm -f $(OBJS) $(LIB)
diff --git a/libraries/thirdparty/ekermit/stm-kermit.c b/libraries/thirdparty/ekermit/stm-kermit.c
new file mode 100644
index 0000000..09eca96
--- /dev/null
+++ b/libraries/thirdparty/ekermit/stm-kermit.c
@@ -0,0 +1,434 @@
+/*
+ * stm-kermit.c
+ * ------------
+ * Interface to the E-Kermit library.
+ *
+ * Copyright (C) 1995, 2011, 
+ * Trustees of Columbia University in the City of New York.
+ * All rights reserved.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the copyright holders nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file is based on unixio.c and main.c from the E-Kermit distribution,
+ * with extensive modifications for the Cryptech environment.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "cdefs.h"
+#include "debug.h"
+#include "platform.h"
+#include "kermit.h"
+
+/* The following symbols, defined in kermit.h, conflict with stm32f429xx.h.
+ * Neither one is used in the file.
+ */
+#undef CR
+#undef SUCCESS
+
+#include "stm-uart.h"
+#include "ringbuf.h"
+#include "stm-kermit.h"
+
+static ringbuf_t uart_ringbuf;
+
+/* current character received from UART */
+static uint8_t uart_rx;
+
+/* Callback for HAL_UART_Receive_IT(). Must be public. */
+void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+    ringbuf_write_char(&uart_ringbuf, uart_rx);
+    HAL_UART_Receive_IT(huart, &uart_rx, 1);
+}
+
+static void uart_init(void)
+{
+    ringbuf_init(&uart_ringbuf);
+    HAL_UART_Receive_IT(&huart_mgmt, &uart_rx, 1);
+}
+
+#ifdef DEBUG
+/* This is public because it's prototyped in debug.h */
+void
+dodebug(int fc, UCHAR * label, UCHAR * sval, long nval)
+{
+    if (label == (UCHAR *)"==========")
+        uart_send_string("\r\n");
+    uart_send_integer(HAL_GetTick(), 8);
+    uart_send_char(' ');
+    
+    if (!label)
+        label = (UCHAR *)"";
+
+    switch (fc) {			/* Function code */
+    case DB_OPN:			/* Open debug log */
+	uart_send_string("DEBUG LOG OPEN\r\n");
+	return;
+    case DB_MSG:			/* Write a message */
+        uart_send_string((char *)label);
+        if (nval) {
+            uart_send_char(' ');
+            uart_send_integer(nval, 1);
+        }
+        uart_send_string("\r\n");
+	return;
+    case DB_CHR:			/* Write label and character */
+        uart_send_string((char *)label);
+        uart_send_string("=[");
+        uart_send_char((uint8_t)nval);
+        uart_send_string("]\r\n");
+	return;
+    case DB_PKT:			/* Log a packet */
+        uart_send_string((char *)label);
+        uart_send_char(' ');
+        uart_send_integer(nval, 1);
+        uart_send_char('[');
+        /* It would be great if we could interpret the packet.
+         * For now, just dump the raw data.
+         */
+        for (int i = 0; i < nval; ++i, ++sval) {
+            if (*sval == '\\')
+                uart_send_string("\\\\");
+            else if (isprint(*sval))
+                uart_send_char(*sval);
+            else {
+                uart_send_char('\\');
+                uart_send_hex(*sval, 2);
+            }
+        }
+        uart_send_string("]\r\n");
+	return;
+    case DB_LOG:			/* Write label and string or number */
+        uart_send_string((char *)label);
+	if (sval) {
+            uart_send_char('[');
+            uart_send_string((char *)sval);
+            uart_send_char(']');
+        }
+	else {
+            uart_send_char('=');
+            uart_send_integer(nval, 1);
+        }
+        uart_send_string("\r\n");
+	return;
+    case DB_CLS:			/* Close debug log */
+        return;
+    }
+}
+#endif
+
+/*  R E A D P K T  --  Read a Kermit packet from the communications device  */
+/*
+  Call with:
+  k   - Kermit struct pointer
+  p   - pointer to read buffer
+  len - length of read buffer
+
+  When reading a packet, this function looks for start of Kermit packet
+  (k->r_soh), then reads everything between it and the end of the packet
+  (k->r_eom) into the indicated buffer.  Returns the number of bytes read, or:
+  0   - timeout or other possibly correctable error;
+  -1   - fatal error, such as loss of connection, or no buffer to read into.
+*/
+
+static int
+readpkt(struct k_data * k, UCHAR *p, int len)
+{
+    int n;
+    short flag;
+    UCHAR x, c;
+#ifdef DEBUG
+    UCHAR * p2;
+#endif
+
+#ifdef F_CTRLC
+    short ccn;
+    ccn = 0;
+#endif
+
+    flag = n = 0;                       /* Init local variables */
+
+#ifdef DEBUG
+    p2 = p;
+#endif
+
+    uart_init();
+
+    while (1) {
+        /* wait for the next character */
+        while (ringbuf_read_char(&uart_ringbuf, &x) == 0) { ; }
+
+        c = (k->parity) ? x & 0x7f : x & 0xff; /* Strip parity */
+
+#ifdef F_CTRLC
+	/* In remote mode only: three consecutive ^C's to quit */
+        if (k->remote && c == (UCHAR) 3) {
+            if (++ccn > 2) {
+		debug(DB_MSG,"readpkt ^C^C^C",0,0);
+		return(-1);
+	    }
+        } else {
+	    ccn = 0;
+	}
+#endif
+
+        if (!flag && c != k->r_soh)	/* No start of packet yet */
+            continue;                     /* so discard these bytes. */
+        if (c == k->r_soh) {		/* Start of packet */
+            flag = 1;                   /* Remember */
+            continue;                   /* But discard. */
+        } else if (c == k->r_eom	/* Packet terminator */
+		   || c == '\012'	/* 1.3: For HyperTerminal */
+            ) {
+#ifdef DEBUG
+	    debug(DB_PKT,"RPKT",p2,n);
+#endif
+            return(n);
+        } else {                        /* Contents of packet */
+            if (n++ > k->r_maxlen)	/* Check length */
+                return(0);
+            else
+                *p++ = x & 0xff;
+        }
+    }
+    debug(DB_MSG,"READPKT FAIL (end)",0,0);
+    return(-1);
+}
+
+/*  T X _ D A T A  --  Writes n bytes of data to communication device.  */
+/*
+  Call with:
+  k = pointer to Kermit struct.
+  p = pointer to data to transmit.
+  n = length.
+  Returns:
+  X_OK on success.
+  X_ERROR on failure to write - i/o error.
+*/
+static int 
+tx_data(struct k_data * k, UCHAR *p, int n)
+{
+    return (uart_send_bytes(STM_UART_MGMT, p, n) == HAL_OK) ? X_OK : X_ERROR;
+}
+
+__weak int kermit_openfile(UCHAR * name) { return X_OK; }
+
+/*  O P E N F I L E  --  Open output file  */
+/*
+  Call with:
+  Pointer to filename.
+  Size in bytes.
+  Creation date in format yyyymmdd hh:mm:ss, e.g. 19950208 14:00:00
+  Mode: 1 = read, 2 = create, 3 = append.
+  Returns:
+  X_OK on success.
+  X_ERROR on failure, including rejection based on name, size, or date.    
+*/
+static int
+openfile(struct k_data * k, UCHAR * s, int mode)
+{
+    int rc;
+
+    switch (mode) {
+    case 2:				/* Write (create) */
+        rc = kermit_openfile(s); 
+	debug(DB_LOG,"openfile write ",s,rc);
+	return(rc);
+    default:
+	debug(DB_LOG,"openfile unsupported mode",0,mode);
+        return(X_ERROR);
+    }
+}
+
+__weak int kermit_writefile(UCHAR * s, int n) { return X_OK; }
+
+/*  W R I T E F I L E  --  Write data to file  */
+/*
+  Call with:
+  Kermit struct
+  String pointer
+  Length
+  Returns:
+  X_OK on success
+  X_ERROR on failure, such as i/o error, space used up, etc
+*/
+static int
+writefile(struct k_data * k, UCHAR * s, int n)
+{
+    debug(DB_LOG,"writefile binary",0,k->binary);
+    return kermit_writefile(s, n);
+}
+
+__weak int kermit_closefile(void) { return X_OK; }
+__weak int kermit_cancelfile(void) { return X_OK; }
+
+/*  C L O S E F I L E  --  Close output file  */
+/*
+  Mode = 1 for input file, mode = 2 or 3 for output file.
+
+  For output files, the character c is the character (if any) from the Z
+  packet data field.  If it is D, it means the file transfer was canceled
+  in midstream by the sender, and the file is therefore incomplete.  This
+  routine should check for that and decide what to do.  It should be
+  harmless to call this routine for a file that that is not open.
+*/
+static int
+closefile(struct k_data * k, UCHAR c, int mode)
+{
+    switch (mode) {
+    case 2:				/* Closing output file */
+	debug(DB_LOG,"closefile (output) name",k->filename,0);
+        if (c == 'D')
+            return kermit_cancelfile();
+        else
+            return kermit_closefile();
+    default:
+	debug(DB_LOG,"closefile unsupported mode",0,mode);
+        return(X_ERROR);
+    }
+}
+
+static UCHAR o_buf[OBUFLEN+8];		/* File output buffer */
+
+int
+kermit_main(void)
+{
+    struct k_data k;                    /* Kermit data structure */
+    struct k_response r;                /* Kermit response structure */
+    int status, rx_len;
+    UCHAR *inbuf;
+    short r_slot;
+
+    debug(DB_MSG,"==========",0,0);
+    debug(DB_OPN,"debug.log",0,0);
+    debug(DB_MSG,"Initializing...",0,0);
+
+/*  Fill in parameters for this run */
+
+    memset(&k, 0, sizeof(k));
+
+    k.remote = 1;			/* 0 = local, 1 = remote */
+    k.xfermode = 1;			/* 0 = automatic, 1 = manual */
+    k.binary = BINARY;			/* 0 = text, 1 = binary */
+    k.parity = P_PARITY;                /* Default parity = PAR_NONE */
+    k.bct = 1;                       	/* Block check type */
+
+/*  Fill in the i/o pointers  */
+  
+    k.obuf   = o_buf;			/* File output buffer */
+    k.obuflen = OBUFLEN;		/* File output buffer length */
+
+/* Fill in function pointers */
+
+    k.rxd    = readpkt;			/* for reading packets */
+    k.txd    = tx_data;			/* for sending packets */
+    k.openf  = openfile;                /* for opening files */
+    k.writef = writefile;               /* for writing to output file */
+    k.closef = closefile;               /* for closing files */
+#ifdef DEBUG
+    k.dbf    = dodebug;			/* for debugging */
+#endif
+
+/* Initialize Kermit protocol */
+
+    status = kermit(K_INIT, &k, 0, 0, "", &r);
+#ifdef DEBUG
+    debug(DB_LOG,"init status:",0,status);
+    debug(DB_LOG,"version:",k.version,0);
+#endif
+    if (status == X_ERROR)
+        return(FAILURE);
+/*
+  Now we read a packet ourselves and call Kermit with it.  Normally, Kermit
+  would read its own packets, but in the embedded context, the device must be
+  free to do other things while waiting for a packet to arrive.  So the real
+  control program might dispatch to other types of tasks, of which Kermit is
+  only one.  But in order to read a packet into Kermit's internal buffer, we
+  have to ask for a buffer address and slot number.
+
+  To interrupt a transfer in progress, set k.cancel to I_FILE to interrupt
+  only the current file, or to I_GROUP to cancel the current file and all
+  remaining files.  To cancel the whole operation in such a way that the
+  both Kermits return an error status, call Kermit with K_ERROR.
+*/
+    while (status != X_DONE) {
+/*
+  Here we block waiting for a packet to come in (unless readpkt times out).
+  Another possibility would be to call inchk() to see if any bytes are waiting
+  to be read, and if not, go do something else for a while, then come back
+  here and check again.
+*/
+        inbuf = getrslot(&k,&r_slot);	/* Allocate a window slot */
+        rx_len = k.rxd(&k,inbuf,P_PKTLEN); /* Try to read a packet */
+/*
+  For simplicity, kermit() ACKs the packet immediately after verifying it was
+  received correctly.  If, afterwards, the control program fails to handle the
+  data correctly (e.g. can't open file, can't write data, can't close file),
+  then it tells Kermit to send an Error packet next time through the loop.
+*/
+        if (rx_len < 1) {               /* No data was read */
+            freerslot(&k,r_slot);	/* So free the window slot */
+            if (rx_len < 0)             /* If there was a fatal error */
+                return(FAILURE);          /* give up */
+
+	    /* This would be another place to dispatch to another task */
+	    /* while waiting for a Kermit packet to show up. */
+
+        }
+        /* Handle the input */
+
+        switch (status = kermit(K_RUN, &k, r_slot, rx_len, "", &r)) {
+        case X_OK:
+#ifdef DEBUG
+/*
+  This shows how, after each packet, you get the protocol state, file name,
+  date, size, and bytes transferred so far.  These can be used in a
+  file-transfer progress display, log, etc.
+*/
+	    debug(DB_LOG,"NAME",r.filename ? r.filename : (UCHAR *)"(NULL)",0);
+	    debug(DB_LOG,"DATE",r.filedate ? r.filedate : (UCHAR *)"(NULL)",0);
+	    debug(DB_LOG,"SIZE",0,r.filesize);
+	    debug(DB_LOG,"STATE",0,r.status);
+	    debug(DB_LOG,"SOFAR",0,r.sofar);
+#endif
+	    /* Maybe do other brief tasks here... */
+	    continue;			/* Keep looping */
+        case X_DONE:
+            debug(DB_LOG,"X_DONE exiting",0,SUCCESS);
+	    break;			/* Finished */
+        case X_ERROR:
+            debug(DB_LOG,"X_ERROR exiting",0,FAILURE);
+	    return(FAILURE);		/* Failed */
+	}
+    }
+    return(SUCCESS);
+}
diff --git a/libraries/thirdparty/ekermit/stm-kermit.h b/libraries/thirdparty/ekermit/stm-kermit.h
new file mode 100644
index 0000000..a2c3436
--- /dev/null
+++ b/libraries/thirdparty/ekermit/stm-kermit.h
@@ -0,0 +1,42 @@
+/*
+ * stm-kermit.h
+ * ------------
+ * Interface to the E-Kermit library.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* return 0 for success, 1 for failure */
+extern int kermit_main(void);
+
+/* return 0 for success, -1 for failure */
+extern int kermit_openfile(unsigned char *name);
+extern int kermit_writefile(unsigned char *buf, int len);
+extern int kermit_closefile(void);
+extern int kermit_cancelfile(void);
diff --git a/projects/ekermit-test/Makefile b/projects/ekermit-test/Makefile
new file mode 100644
index 0000000..b4fab70
--- /dev/null
+++ b/projects/ekermit-test/Makefile
@@ -0,0 +1,22 @@
+TEST = ekermit-test
+
+OBJS = ../libhal-test/printf.o
+
+BOARD_OBJS += $(TOPLEVEL)/sdram-malloc.o
+
+CFLAGS += -I$(EKERMIT_DIR)
+
+LIBS += $(EKERMIT_DIR)/libekermit.a
+
+all: $(TEST:=.elf)
+
+%.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS)
+	$(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
+	$(OBJCOPY) -O binary $*.elf $*.bin
+	$(SIZE) $*.elf
+
+clean:
+	rm -f *.o
+	rm -f *.elf
+	rm -f *.bin
+	rm -f *.map
diff --git a/projects/ekermit-test/ekermit-test.c b/projects/ekermit-test/ekermit-test.c
new file mode 100644
index 0000000..3b71a69
--- /dev/null
+++ b/projects/ekermit-test/ekermit-test.c
@@ -0,0 +1,167 @@
+/*
+ * ekermit-test.c
+ * --------------
+ * A test program for the E-Kermit library.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This receives one or more files from a kermit client (e.g. C-Kermit),
+ * and stores them in a minimal file system on SDRAM.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "stm-init.h"
+#include "stm-sdram.h"
+#include "sdram-malloc.h"
+#include "stm-kermit.h"
+
+/* alignment for file allocations */
+#define ALIGN 16
+
+/* maximum length of file name */
+#define NAMELEN 32
+
+/* maximum number of files */
+#define NFILE 4
+
+typedef struct {
+  char name[NAMELEN];
+  uint8_t *loc;
+  size_t len;
+} filetab_t;
+filetab_t filetab[NFILE], *curfile;
+int nfile;
+
+#ifdef DUMP
+static void hexdump(uint8_t *buf, int len)
+{
+    for ( ; len > 0; buf += 16, len -= 16) {
+        int plen = (len > 16) ? 16 : len;
+        int i;
+        for (i = 0; i < plen; ++i)
+            printf("%02x ", buf[i]);
+        for ( ; i < 16; ++i)
+            printf("   ");
+        printf("| ");
+        for (i = 0; i < plen; ++i)
+            printf("%c", isprint(buf[i]) ? buf[i] : ' ');
+        printf("\n");
+    }
+}
+#endif
+
+/* Override weak function defintions for callouts in stm-kermit.c */
+
+/* Called when kermit receives an F (file) packet
+ */
+int kermit_openfile(unsigned char *name)
+{
+    if (nfile == NFILE) {
+        curfile = NULL;
+        return -1;
+    }
+    curfile = &filetab[nfile];
+    strncpy(curfile->name, (char *)name, sizeof(curfile->name));
+    curfile->loc = sdram_malloc(0);
+    if (curfile->loc == NULL) {
+        curfile = NULL;
+        return -1;
+    }
+    curfile->len = 0;
+    ++nfile;
+    return 0;
+}
+
+/* Called when kermit's receive buffer is full, after some number of D
+ * (data) packets
+ */
+int kermit_writefile(unsigned char *buf, int len)
+{
+    if (curfile == NULL)
+        return -1;
+    uint8_t *writeptr = sdram_malloc(len);
+    if (writeptr == NULL)
+        return -1;
+    memcpy(writeptr, buf, len);
+    curfile->len += len;
+    return 0;
+}
+
+/* Called when kermit receives a Z (EOF) packet
+ */
+int kermit_closefile(void)
+{
+    if (curfile == NULL)
+        return -1;
+    int pad = ALIGN - (curfile->len & (ALIGN - 1));
+    if (sdram_malloc(pad) == NULL)
+        return -1;
+    curfile = NULL;
+    return 0;
+}
+
+/* Called when kermit receives a Z (EOF) packet with a D (discard) flag
+ */
+int kermit_cancelfile(void)
+{
+    if (curfile == NULL)
+        return -1;
+    sdram_free(curfile->loc);
+    memset(curfile, 0, sizeof(*curfile));
+    --nfile;
+    return 0;
+}
+
+/* The main function is pretty simple, because the kermit library does all
+ * the work out of sight.
+ */
+int main(void)
+{
+    stm_init();
+    sdram_init();
+
+    while (1) {
+        memset((void *)filetab, 0, sizeof(filetab));
+        curfile = NULL;
+        nfile = 0;
+        kermit_main();
+        for (int i = 0; i < nfile; ++i) {
+            filetab_t *f = &filetab[i];
+            printf("%d. %-16s %p %d\n", i, f->name, f->loc, f->len);
+#ifdef DUMP
+            hexdump(f->loc, f->len);
+#endif
+            sdram_free(f->loc);
+        }
+    }
+}



More information about the Commits mailing list