Commit 56613a8c authored by Alessandro Rubini's avatar Alessandro Rubini

arch-bathos: completed

There are still some details to fix, but it basically works
(modulo the still-missing features in bathos)

EOF
parent 9fd75bfb
......@@ -8,7 +8,7 @@ CFLAGS += -ffreestanding -Os
BATHOS_ROOT ?= ../bathos
BATHOS_ARCH ?= lpc2104
CFLAGS += -I$(BATHOS_ROOT)/include -I$(BATHOS)/arch-$(BATHOS_ARCH)
CFLAGS += -I$(BATHOS_ROOT)/include -I$(BATHOS_ROOT)/arch-$(BATHOS_ARCH) -Itools
# Let's use the pp_printf we already have in bathos
CONFIG_NO_PRINTF = y
......@@ -24,6 +24,7 @@ LIBS += -L$A -larch
OBJ-libarch := \
$A/bathos-task.o \
$A/memcmp.o \
lib/dump-funcs.o \
lib/div64.o
# We only support our own time operations
......
#include <ppsi/ppsi.h>
#include <bathos/bathos.h>
#include <bathos/jiffies.h>
#include <bathos/io.h>
#include <ppsi/ppsi.h>
/* Again, allow env-based setup */
#ifndef PP_DIAG_VERBOSITY
#define PP_DIAG_VERBOSITY 0
#define PP_DIAG_VERBOSITY "0"
#endif
const int pp_diag_verbosity = PP_DIAG_VERBOSITY;
const int pp_diag_verbosity; /* not really used by now, to be removed */
static struct pp_globals ppg_static;
static struct pp_instance ppi_static;
/* ppi fields */
static DSDefault defaultDS;
static DSCurrent currentDS;
static DSParent parentDS;
static DSPort portDS;
static DSTimeProperties timePropertiesDS;
static struct pp_servo servo;
/* At boot, initialize the status for this task */
static int ppsi_init(void *status)
{
struct pp_instance *ppi = status;
struct pp_globals *ppg = &ppg_static;
printf("%s: verbosity string: \"%s\"\n", __func__,
PP_DIAG_VERBOSITY);
ppi->flags = pp_diag_parse(PP_DIAG_VERBOSITY);
ppi->glbs = ppg;
ppg->defaultDS = &defaultDS;
ppg->currentDS = &currentDS;
ppg->parentDS = &parentDS;
ppi->portDS = &portDS;
ppg->timePropertiesDS = &timePropertiesDS;
ppg->servo = &servo;
ppg->arch_data = NULL;
ppi->n_ops = &DEFAULT_NET_OPS;
ppi->t_ops = &DEFAULT_TIME_OPS;
ppi->ethernet_mode = PP_DEFAULT_ETHERNET_MODE;
NP(ppi)->ptp_offset = 14 /*ETH_HLEN */;
ppi->iface_name = "eth0"; /* unused by bathos */
ppg->rt_opts = &default_rt_opts;
ppi->is_new_state = 1;
ppi->state = PPS_INITIALIZING;
pp_open_globals(ppg);
/* The actual sockets are opened in state-initializing */
return 0;
}
/* This runs periodically */
static void *ppsi_job(void *arg)
{
struct pp_instance *ppi = arg;
struct ethhdr {
unsigned char h_dest[6];
unsigned char h_source[6];
uint16_t h_proto;
} *hdr = ppi->rx_frame;
int i, minsize = sizeof(*hdr), delay_ms;
static unsigned long next_to; /* bad: not multi-task */
/* If the network is not inited, don't even try to receive */
if (NP(ppi)->ch[PP_NP_EVT].custom == NULL) {
delay_ms = pp_state_machine(ppi, NULL, 0);
goto out_calc;
}
/* We have no such thing as select(), so poll for a frame */
do {
i = ppi->n_ops->recv(ppi, ppi->rx_frame,
PP_MAX_FRAME_LENGTH - 4,
&ppi->last_rcv_time);
} while ((i > minsize) && (ntohs(hdr->h_proto) != ETH_P_1588));
/* If no frame and no timeout yet, return */
if (i < minsize && next_to && time_before(jiffies, next_to))
return arg;
if (i > minsize) /* State machine with a frame */
delay_ms = pp_state_machine(ppi, ppi->rx_ptp,
i - NP(ppi)->ptp_offset);
else /* State machine without a frame */
delay_ms = pp_state_machine(ppi, NULL, 0);
out_calc:
next_to = ppi->t_ops->calc_timeout(ppi, delay_ms);
return arg;
}
static struct bathos_task __task t_pwm = {
.name = "ppsi",
.period = HZ / 10,
.init = ppsi_init,
.job = ppsi_job,
.arg = &ppi_static,
.release = 2 * HZ,
};
/*
* Alessandro Rubini for CERN, 2011 -- public domain
* (Bathos code heavily based on bare code)
*/
/* Socket interface for bathos. Currently only enc28 device */
#include <bathos/bathos.h>
#include <bathos/enc28j60.h>
#include <arch/gpio.h>
#include <arch/spi.h>
#include <ppsi/ppsi.h>
#include "ptpdump.h"
/*
* SPI configuration: we need to declare both the config and the
* device since we have no malloc in this crappy OS.
* Note: The hardware configuration is hardwired here.
*/
#define GPIO_CS 10
#define GPIO_OTHER_CS 9 /* turn this off (high) */
static const struct spi_cfg spi_cfg = {
.gpio_cs = GPIO_CS,
.pol = 0,
.phase = 0,
.devn = 0,
};
static struct spi_dev spi_dev = {
.cfg = &spi_cfg,
};
/* ENC28 configuration */
static const struct enc28_cfg enc28_cfg = {
/* This is an IP address in my network */
.ipaddr = {192, 168,16, 201},
/* And this is in the private range */
.macaddr = {0x02, 0x33, 0x44, 0x55, 0x66, 0x77},
};
static struct enc28_dev enc28_dev = {
.spi_dev = &spi_dev,
.cfg = &enc28_cfg,
};
static int enc28_init(void)
{
/* My board has another device on SPI: disable its CS on other_cs */
gpio_dir_af(GPIO_OTHER_CS, 1, 1, 0);
gpio_set(GPIO_OTHER_CS, 1);
/* This is our gpio 10 */
gpio_dir_af(GPIO_CS, 1, 1, 0);
gpio_set(GPIO_CS, 1);
enc28_create(&enc28_dev);
return 0;
}
static void enc28_exit(void)
{
enc28_destroy(&enc28_dev);
}
/* To open a channel we open the enc28, and that's it */
static int bathos_open_ch(struct pp_instance *ppi, char *ifname)
{
if (!ppi->ethernet_mode) {
pp_printf("%s: can't init UDP channels yet\n", __func__);
return -1;
}
pp_printf("%s: opening %s\n", __func__, ifname);
enc28_init();
memcpy(NP(ppi)->ch[PP_NP_GEN].addr, enc28_cfg.macaddr, 6);
memcpy(NP(ppi)->ch[PP_NP_EVT].addr, enc28_cfg.macaddr, 6);
NP(ppi)->ch[PP_NP_GEN].custom = &enc28_dev;
NP(ppi)->ch[PP_NP_EVT].custom = &enc28_dev;
return 0;
}
static int bathos_net_exit(struct pp_instance *ppi)
{
if (NP(ppi)->ch[PP_NP_EVT].custom)
enc28_exit();
NP(ppi)->ch[PP_NP_EVT].custom = NULL;
NP(ppi)->ch[PP_NP_GEN].custom = NULL;
return 0;
}
/* This function must be able to be called twice, and clean-up internally */
static int bathos_net_init(struct pp_instance *ppi)
{
bathos_net_exit(ppi);
/* The buffer is inside ppi, but we need to set pointers and align */
pp_prepare_pointers(ppi);
if (!ppi->ethernet_mode) {
pp_printf("%s: can't init UDP channels yet\n", __func__);
return -1;
}
pp_diag(ppi, frames, 1, "%s: Ethernet mode\n", __func__);
/* raw sockets implementation always use gen socket */
return bathos_open_ch(ppi, ppi->iface_name);
}
static int bathos_net_recv(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t)
{
int ret;
ret = enc28_recv(NP(ppi)->ch[PP_NP_GEN].custom, pkt, len);
if (t && ret > 0)
ppi->t_ops->get(ppi, t);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
dump_1588pkt("recv: ", pkt, ret, t);
return ret;
}
static int bathos_net_send(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t, int chtype, int use_pdelay_addr)
{
struct ethhdr {
unsigned char h_dest[6];
unsigned char h_source[6];
uint16_t h_proto;
} __attribute__((packed)) *hdr = pkt;
int ret;
hdr->h_proto = htons(ETH_P_1588);
memcpy(hdr->h_dest, PP_MCAST_MACADDRESS, 6);
/* raw socket implementation always uses gen socket */
memcpy(hdr->h_source, NP(ppi)->ch[PP_NP_GEN].addr, 6);
if (t)
ppi->t_ops->get(ppi, t);
ret = enc28_send(NP(ppi)->ch[chtype].custom, pkt, len);
if (ret > 0 && pp_diag_allow(ppi, frames, 2))
dump_1588pkt("send: ", pkt, len, t);
return ret;
}
struct pp_network_operations bathos_net_ops = {
.init = bathos_net_init,
.exit = bathos_net_exit,
.recv = bathos_net_recv,
.send = bathos_net_send,
};
/*
* Alessandro Rubini for CERN, 2013 -- LGPL 2.1 or later
* (Bathos code heavily based on bare code)
*/
#include <bathos/bathos.h>
#include <bathos/jiffies.h>
#include <bathos/io.h>
#include <ppsi/ppsi.h>
static unsigned long long jiffies_base;
static const int nsec_per_jiffy = 1000 * 1000 * 1000 / HZ;
static int bathos_time_get(struct pp_instance *ppi, TimeInternal *t)
{
/* FIXME: horrible time-keeping based on jiffies */
unsigned long long j = jiffies_base + jiffies;
/* FIXME: Use our own do_div to avoid libgcc mess */
t->seconds = j / HZ;
t->nanoseconds = (j % HZ) * nsec_per_jiffy;
if (!(pp_global_flags & PP_FLAG_NOTIMELOG))
pp_diag(ppi, time, 2, "%s: %9li.%06li\n", __func__,
(long)t->seconds, (long)t->nanoseconds);
return 0;
}
static int bathos_time_set(struct pp_instance *ppi, TimeInternal *t)
{
unsigned long long j = (long long)(t->seconds) * HZ
+ (t->nanoseconds + nsec_per_jiffy / 2) / nsec_per_jiffy;
jiffies_base = j - jiffies;
pp_diag(ppi, time, 1, "%s: %9li.%06li\n", __func__,
(long)t->seconds, (long)t->nanoseconds);
return 0;
}
static int bathos_time_adjust(struct pp_instance *ppi, long offset_ns,
long freq_ppm)
{
/* FIXME: no adj-time is present */
pp_diag(ppi, time, 1, "%s: %li %li\n", __func__, offset_ns, freq_ppm);
return 0;
}
int bathos_time_adjust_offset(struct pp_instance *ppi, long offset_ns)
{
return bathos_time_adjust(ppi, offset_ns, 0);
}
int bathos_time_adjust_freq(struct pp_instance *ppi, long freq_ppm)
{
return bathos_time_adjust(ppi, 0, freq_ppm);
}
/*
* Unfortuanately (my own bug, it seems), the timeout is not expressed
* in generic "jiffies", but rather in milliseconds. Currently the fix
* is setting HZ to 1000 in bathos.
*/
#if HZ != 1000
#error "HZ must be 1000, until the code is fixed"
#endif
static unsigned long bathos_calc_timeout(struct pp_instance *ppi, int millisec)
{
/* ms to jiffies... */
unsigned long j = millisec * 1000 * 1000 / nsec_per_jiffy;
return jiffies + j ?: 1 /* cannot return 0 */;
}
struct pp_time_operations bathos_time_ops = {
.get = bathos_time_get,
.set = bathos_time_set,
.adjust = bathos_time_adjust,
.adjust_offset = bathos_time_adjust_offset,
.adjust_freq = bathos_time_adjust_freq,
.calc_timeout = bathos_calc_timeout,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment