creole interface

This commit is contained in:
Peter McGoron 2023-03-23 22:25:29 +00:00
parent 8006853e6c
commit cbdd0daaa6
6 changed files with 165 additions and 95 deletions

2
creole

@ -1 +1 @@
Subproject commit 6d30be57f7c1853eb1fe26e91e0d0aae8811383b Subproject commit c18db4be57214903f2b1f6d5a7943eb40f644024

View File

@ -1,59 +1,31 @@
#include <zephyr/zephyr.h> #include <zephyr/zephyr.h>
#include <zephyr/sys/printk.h> #include <zephyr/sys/printk.h>
#include <zephyr/net/socket.h>
#include "buf.h" #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 int
buf_writevf(struct bufptr *bp, const char *fmt, va_list va) buf_writevf(struct bufptr *bp, const char *fmt, va_list va)
{ {
int w;
/* vsnprintk() returns the amount of bytes that would /* vsnprintk() returns the amount of bytes that would
* be stored in the buffer if the buffer was big enough, * be stored in the buffer if the buffer was big enough,
* excluding the NUL terminator. * excluding the NUL terminator.
* The function will _always_ write a NUL terminator * The function will _always_ write a NUL terminator
* unless bp->left == 0. * unless bp->left == 0.
*/ */
w = vsnprintk(bp->p, bp->left, fmt, va); int w = vsnprintk(bp->p, bp->left, fmt, va);
if (w < 0) if (w < 0)
return BUF_WRITE_ERR; 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) { if (w >= bp->left) {
size_t oldleft = bp->left; return w - bp->left + 1;
buf->p += bp->left - 1;
bp->left = 1;
return w - oldleft + 1;
} else { } else {
bp->p += w; bp->p += w;
bp->left -= w; bp->left -= w;
@ -64,10 +36,9 @@ buf_writevf(struct bufptr *bp, const char *fmt, va_list va)
int int
buf_writef(struct bufptr *bp, const char *fmt, ...) buf_writef(struct bufptr *bp, const char *fmt, ...)
{ {
int r;
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
r = buf_writevf(bp, fmt, va); int r = buf_writevf(bp, fmt, va);
va_end(va); va_end(va);
return r; return r;
} }

View File

@ -12,28 +12,10 @@ struct bufptr {
enum { enum {
BUF_OK = 0, 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. /* Write a formatted string to bp.
* This function uses printf(), which means that it deals with * This function uses printf(), which means that it deals with
* writing _C-strings_, not unterminated buffers. * writing _C-strings_, not unterminated buffers.

View File

@ -1,8 +1,10 @@
#include <sys_clock.h> #include <sys_clock.h>
#include <sys/util.h>
#include "control_loop_cmds.h" #include "control_loop_cmds.h"
#include "creole.h" #include "creole.h"
#include "creole_upsilon.h" #include "creole_upsilon.h"
#include "pin_io.h" #include "pin_io.h"
#include "creole.h"
static inline uint32_t static inline uint32_t
sign_extend(uint32_t in, unsigned len) sign_extend(uint32_t in, unsigned len)
@ -67,7 +69,7 @@ creole_word
upsilon_usec(creole_word usec) upsilon_usec(creole_word usec)
{ {
k_sleep(K_USEC(usec)); k_sleep(K_USEC(usec));
return 0; return 1;
} }
creole_word creole_word
@ -82,7 +84,7 @@ upsilon_control_loop_read(creole_word *high_reg,
*low_reg = cl_word_out[1]; *low_reg = cl_word_out[1];
*cl_start_cmd = 0; *cl_start_cmd = 0;
return 0; return 1;
} }
creole_word creole_word
@ -97,32 +99,85 @@ upsilon_control_loop_write(creole_word high_val,
while (!*cl_finish_cmd); while (!*cl_finish_cmd);
*cl_start_cmd = 0; *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 creole_word
upsilon_load_waveform(struct creole_env *env, creole_word slot, upsilon_load_waveform(struct creole_env *env, creole_word slot,
creole_word db) creole_word db)
{ {
/* TODO */ 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; 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 creole_word
upsilon_exec_waveform(creole_word slot, creole_word dac) upsilon_arm_waveform(creole_word slot, creole_word hof, creole_word wait)
{ {
/* TODO */ *wf_halt_on_finished[slot] = hof;
return 0; *wf_time_to_wait[slot] = wait;
*wf_arm[slot] = 1;
if (wait) {
while (!*wf_finished[slot]);
*wf_arm[slot] = 0;
} }
return 1;
}
creole_word creole_word
upsilon_sendval(creole_word num) upsilon_disarm_waveform(creole_word slot)
{ {
/* TODO */ *wf_arm[slot] = 0;
return 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 creole_word
upsilon_senddat(struct creole_env *env, creole_word db) upsilon_senddat(struct creole_env *env, creole_word db)
{ {
/* TODO */ 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; return 0;
buf[bp.left++] = w.word;
}
return sock_write_buf(env->fd, &bp);
} }

View File

@ -4,6 +4,7 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include "sock.h" #include "sock.h"
#include "buf.h"
LOG_MODULE_REGISTER(sock); LOG_MODULE_REGISTER(sock);
@ -47,6 +48,9 @@ server_accept_client(int server)
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t len = sizeof(addr); socklen_t len = sizeof(addr);
/* Accept clients in a loop. This is halting so other threads will
* be able to process clients.
*/
do { do {
client = zsock_accept(server, (struct sockaddr *)&addr, &len); client = zsock_accept(server, (struct sockaddr *)&addr, &len);
if (client < 0) if (client < 0)
@ -59,34 +63,71 @@ server_accept_client(int server)
return client; return client;
} }
int bool
sock_vprintf(int sock, char *buf, int buflen, char *fmt, va_list va) sock_read_buf(int sock, struct bufptr *bp)
{ {
int w = vsnprintk(buf, buflen, fmt, va); if (bp->left < 2)
if (w < 0) return false;
return b;
else if (w <= buflen)
return w - buflen;
ssize_t left = w; ssize_t l = zsock_recv(sock, bp->p, bp->left - 1, 0);
char *p = buf; if (l < 0)
while (left > 0) { return false;
ssize_t i = zsock_send(sock, p, left, 0);
if (i < 0) bp->left -= l;
return 0; bp->p += l;
p += i; if (bp->left == 0) {
left -= i; 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 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_list va;
va_start(va, fmt); va_start(va, fmt);
int r = sock_vprintf(sock, buf, buflen, fmt, va); bool b = sock_vprintf(sock, bp, fmt, va);
va_end(va); va_end(va);
return r; return b;
} }

View File

@ -1,7 +1,28 @@
#pragma once #pragma once
#include <stdarg.h>
#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); 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); 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, ...);