diff --git a/creole b/creole index 6d30be5..c18db4b 160000 --- a/creole +++ b/creole @@ -1 +1 @@ -Subproject commit 6d30be57f7c1853eb1fe26e91e0d0aae8811383b +Subproject commit c18db4be57214903f2b1f6d5a7943eb40f644024 diff --git a/software/src/buf.c b/software/src/buf.c index 8caccc5..6d042e2 100644 --- a/software/src/buf.c +++ b/software/src/buf.c @@ -1,59 +1,31 @@ #include #include -#include #include "buf.h" -bool -buf_read_sock(int sock, struct bufptr *bp) -{ - if (bp->left < 2) - return false; - - ssize_t l = zsock_recv(sock, bp->p, bp->left - 1, 0); - if (l < 0) - return false; - - bp->left -= l; - bp->p += l; - *bp->p = 0; - return true; -} - -bool -buf_write_sock(int sock, struct bufptr *bp) -{ - while (bp->left) { - ssize_t l = zsock_send(sock, bp->p, bp->left, 0); - if (l < 0) - return false; - bp->p += l; - bp->left -= l; - } - - return true; -} - int buf_writevf(struct bufptr *bp, const char *fmt, va_list va) { - int w; - /* vsnprintk() returns the amount of bytes that would * be stored in the buffer if the buffer was big enough, * excluding the NUL terminator. * The function will _always_ write a NUL terminator * unless bp->left == 0. */ - w = vsnprintk(bp->p, bp->left, fmt, va); + int w = vsnprintk(bp->p, bp->left, fmt, va); if (w < 0) return BUF_WRITE_ERR; + /* Return the number of bytes that are required to be + * written. + * Do not increment the buffer pointer, the truncated + * data may not be safe. + * Since w is the amount of required bytes minus the NUL + * terminator, w == bp->left is still an out-of-memory + * situation. + */ if (w >= bp->left) { - size_t oldleft = bp->left; - buf->p += bp->left - 1; - bp->left = 1; - return w - oldleft + 1; + return w - bp->left + 1; } else { bp->p += w; bp->left -= w; @@ -64,10 +36,9 @@ buf_writevf(struct bufptr *bp, const char *fmt, va_list va) int buf_writef(struct bufptr *bp, const char *fmt, ...) { - int r; va_list va; va_start(va, fmt); - r = buf_writevf(bp, fmt, va); + int r = buf_writevf(bp, fmt, va); va_end(va); return r; } diff --git a/software/src/buf.h b/software/src/buf.h index d7555a4..ab0ed4a 100644 --- a/software/src/buf.h +++ b/software/src/buf.h @@ -12,28 +12,10 @@ struct bufptr { enum { BUF_OK = 0, - BUF_WRITE_ERR = -1 + BUF_WRITE_ERR = -1, + BUF_SOCK_ERR = -2 }; -/* Read from the socket into the buffer. - * This function is meant to be called multiple times on the - * same struct. The controller loads bp->left with the amount - * of bytes it wishes to read, and continues until bp->left == 0. - * - * This function returns false if there was an error reading - * from the socket. - * A read of 0 bytes returns true. - */ -bool buf_read_sock(int sock, struct bufptr *bp); - -/* Write from the bufptr into a socket. - * This function is meant to be called once per prepared bufptr. - * - * This function returns false if there was an error on the - * socket. - */ -bool buf_write_sock(int sock, struct bufptr *bp); - /* Write a formatted string to bp. * This function uses printf(), which means that it deals with * writing _C-strings_, not unterminated buffers. diff --git a/software/src/creole_interface.c b/software/src/creole_interface.c index 4d276c3..e284a5f 100644 --- a/software/src/creole_interface.c +++ b/software/src/creole_interface.c @@ -1,8 +1,10 @@ #include +#include #include "control_loop_cmds.h" #include "creole.h" #include "creole_upsilon.h" #include "pin_io.h" +#include "creole.h" static inline uint32_t sign_extend(uint32_t in, unsigned len) @@ -67,7 +69,7 @@ creole_word upsilon_usec(creole_word usec) { k_sleep(K_USEC(usec)); - return 0; + return 1; } creole_word @@ -82,7 +84,7 @@ upsilon_control_loop_read(creole_word *high_reg, *low_reg = cl_word_out[1]; *cl_start_cmd = 0; - return 0; + return 1; } creole_word @@ -97,32 +99,85 @@ upsilon_control_loop_write(creole_word high_val, while (!*cl_finish_cmd); *cl_start_cmd = 0; - return 0; + return 1; } +static size_t +load_into_array(const struct creole_reader *start, creole_word *buf, size_t buflen) +{ + size_t i = 0; + struct creole_word w; + struct creole_reader r = start; + + while (creole_decode(&r, &w) && i < buflen) { + buf[i++] = w.word; + } + + return i; +} + +#define MAX_WL_SIZE 4096 creole_word upsilon_load_waveform(struct creole_env *env, creole_word slot, creole_word db) { - /* TODO */ - return 0; + creole_word buf[MAX_WL_SIZE]; + size_t len = load_into_array(env->dats[db], buf, ARRAY_SIZE(buf)); + + if (len != MAX_WL_SIZE) + return 0; + + *wf_start_addr[slot] = &buf; + *wf_refresh_start[slot] = 1; + while (!*wf_refresh_finished[slot]); + *wf_refresh_start[slot] = 0; + + return 1; } creole_word -upsilon_exec_waveform(creole_word slot, creole_word dac) +upsilon_arm_waveform(creole_word slot, creole_word hof, creole_word wait) { - /* TODO */ - return 0; + *wf_halt_on_finished[slot] = hof; + *wf_time_to_wait[slot] = wait; + *wf_arm[slot] = 1; + + if (wait) { + while (!*wf_finished[slot]); + *wf_arm[slot] = 0; + } + + return 1; } + creole_word -upsilon_sendval(creole_word num) +upsilon_disarm_waveform(creole_word slot) { - /* TODO */ - return 0; + *wf_arm[slot] = 0; + return 1; +} + +creole_word +upsilon_sendval(struct creole_env *env, creole_word num) +{ + char buf[32]; + struct bufptr bp = {buf, sizeof(buf)}; + + return sock_printf(env->fd, &bp, "%u", num) == BUF_OK; } creole_word upsilon_senddat(struct creole_env *env, creole_word db) { - /* TODO */ - return 0; + char buf[128]; + struct bufptr bp = {buf, 0}; + struct creole_word w; + struct creole_reader r = start; + + while (creole_decode(&r, &w) && bp.left < buflen) { + if (w.word > 0xFF) + return 0; + buf[bp.left++] = w.word; + } + + return sock_write_buf(env->fd, &bp); } diff --git a/software/src/sock.c b/software/src/sock.c index bee911b..e662303 100644 --- a/software/src/sock.c +++ b/software/src/sock.c @@ -4,6 +4,7 @@ #include #include #include "sock.h" +#include "buf.h" LOG_MODULE_REGISTER(sock); @@ -47,6 +48,9 @@ server_accept_client(int server) struct sockaddr_in addr; socklen_t len = sizeof(addr); + /* Accept clients in a loop. This is halting so other threads will + * be able to process clients. + */ do { client = zsock_accept(server, (struct sockaddr *)&addr, &len); if (client < 0) @@ -59,34 +63,71 @@ server_accept_client(int server) return client; } -int -sock_vprintf(int sock, char *buf, int buflen, char *fmt, va_list va) +bool +sock_read_buf(int sock, struct bufptr *bp) { - int w = vsnprintk(buf, buflen, fmt, va); - if (w < 0) - return b; - else if (w <= buflen) - return w - buflen; + if (bp->left < 2) + return false; - ssize_t left = w; - char *p = buf; - while (left > 0) { - ssize_t i = zsock_send(sock, p, left, 0); - if (i < 0) - return 0; - p += i; - left -= i; + ssize_t l = zsock_recv(sock, bp->p, bp->left - 1, 0); + if (l < 0) + return false; + + bp->left -= l; + bp->p += l; + if (bp->left == 0) { + LOG_ERR("internal out of bounds error in %s", __func__); + k_fatal_halt(K_ERR_KERNEL_PANIC); } - return w; + *bp->p = 0; + return true; +} + +bool +sock_write_buf(int sock, struct bufptr *bp) +{ + /* Since send may not send all data in the buffer at once, + * loop until it sends all data (or fails). + */ + while (bp->left) { + ssize_t l = zsock_send(sock, bp->p, bp->left, 0); + if (l < 0) + return false; + bp->p += l; + bp->left -= l; + } + + return true; } int -sock_printf(int sock, char *buf, int buflen, char *fmt, ...) +sock_vprintf(int sock, struct bufptr *bp, const char *fmt, va_list va) +{ + int r = buf_writevf(bp, fmt, va); + struct bufptr store_bp = *bp; + if (r != BUF_OK) + return r; + + /* The difference between the initial and final values of + * `left` is the amount of bytes written to the buffer. + * Set left to this difference so that the only thing sent + * is the bytes written by buf_writevf. + */ + store_bp.left -= bp->left; + if (!sock_write_buf(sock, &store_bp)) { + return BUF_SOCK_ERR; + } else { + return BUF_OK; + } +} + +int +sock_printf(int sock, struct bufptr *bp, const char *fmt, ...) { va_list va; va_start(va, fmt); - int r = sock_vprintf(sock, buf, buflen, fmt, va); + bool b = sock_vprintf(sock, bp, fmt, va); va_end(va); - return r; + return b; } diff --git a/software/src/sock.h b/software/src/sock.h index fe45efe..fef6661 100644 --- a/software/src/sock.h +++ b/software/src/sock.h @@ -1,7 +1,28 @@ #pragma once +#include +#include "buf.h" -/* Initialize server to listen on the port passed as an argument. */ +/* Initialize server to listen on the port passed as an argument. + */ int server_init_sock(int port); -/* Accept a client and allocate a file descriptor for the client. */ +/* Accept a client and allocate a file descriptor for the client. + */ int server_accept_client(int server); + +/* Read data into buffer. Returns false if error occurs. This is + * raw binary (no NUL termination). + */ +bool sock_read_buf(int sock, struct bufptr *bp); + +/* Write raw buffer data into socket. This data is raw binary and + * does not have to be NUL terminated. + */ +bool sock_write_buf(int sock, struct bufptr *bp); + +/* Write formatted string into socket. The user must provide a + * buffer into which the formatted string is written. These return + * with a buf.h error, or BUF_OK when successful. + */ +int sock_vprintf(int sock, struct bufptr *bp, const char *fmt, va_list va); +int sock_printf(int sock, struct bufptr *bp, const char *fmt, ...);