runtime: get IP and MAC from flash storage

This commit is contained in:
Sebastien Bourdeauducq 2015-05-01 12:34:47 +08:00
parent 56c85dd2cb
commit d3753c9643
4 changed files with 284 additions and 207 deletions

View File

@ -1,6 +1,6 @@
include $(MSCDIR)/software/common.mak include $(MSCDIR)/software/common.mak
OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o main.o OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o kserver.o main.o
OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o dds.o OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o dds.o
CFLAGS += -Ilwip/src/include -Iliblwip CFLAGS += -Ilwip/src/include -Iliblwip

215
soc/runtime/kserver.c Normal file
View File

@ -0,0 +1,215 @@
#include <generated/csr.h>
#ifdef CSR_ETHMAC_BASE
#include <netif/etharp.h>
#include <netif/liteethif.h>
#include <lwip/init.h>
#include <lwip/memp.h>
#include <lwip/ip4_addr.h>
#include <lwip/ip4.h>
#include <lwip/netif.h>
#include <lwip/sys.h>
#include <lwip/tcp.h>
#include <lwip/timers.h>
#include "session.h"
#include "kserver.h"
struct kserver_connstate {
int magic_recognized;
struct pbuf *rp;
int rp_offset;
};
static struct kserver_connstate *cs_new(void)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)mem_malloc(sizeof(struct kserver_connstate));
if(!cs)
return NULL;
cs->magic_recognized = 0;
cs->rp = NULL;
cs->rp_offset = 0;
return cs;
}
static void cs_free(struct kserver_connstate *cs)
{
if(cs->rp)
pbuf_free(cs->rp);
mem_free(cs);
}
static const char kserver_magic[] = "ARTIQ coredev\n";
static int magic_ok(struct kserver_connstate *cs)
{
return cs->magic_recognized >= 14;
}
static struct kserver_connstate *active_cs;
static struct tcp_pcb *active_pcb;
static void kserver_close(struct kserver_connstate *cs, struct tcp_pcb *pcb)
{
if(cs == active_cs) {
session_end();
active_cs = NULL;
active_pcb = NULL;
}
/* lwip loves to call back with broken pointers. Prevent that. */
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_err(pcb, NULL);
cs_free(cs);
tcp_close(pcb);
}
static err_t kserver_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)arg;
if(p) {
if(cs->rp)
pbuf_cat(cs->rp, p);
else {
cs->rp = p;
cs->rp_offset = 0;
}
} else
kserver_close(cs, pcb);
return ERR_OK;
}
static err_t kserver_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
session_ack_mem(len);
return ERR_OK;
}
static void tcp_pcb_service(void *arg, struct tcp_pcb *pcb)
{
struct kserver_connstate *cs;
int remaining_in_pbuf;
char *rpp;
struct pbuf *next;
int r;
cs = (struct kserver_connstate *)arg;
while(cs->rp) {
remaining_in_pbuf = cs->rp->len - cs->rp_offset;
rpp = (char *)cs->rp->payload;
while(remaining_in_pbuf > 0) {
if(cs == active_cs) {
r = session_input(&rpp[cs->rp_offset], remaining_in_pbuf);
if(r > 0) {
tcp_recved(pcb, r);
cs->rp_offset += r;
remaining_in_pbuf -= r;
} else if(r == 0)
return;
else
kserver_close(cs, pcb);
} else {
if(rpp[cs->rp_offset] == kserver_magic[cs->magic_recognized]) {
cs->magic_recognized++;
if(magic_ok(cs)) {
if(active_cs)
kserver_close(active_cs, active_pcb);
session_start();
active_cs = cs;
active_pcb = pcb;
tcp_sent(pcb, kserver_sent);
}
} else {
kserver_close(cs, pcb);
return;
}
remaining_in_pbuf--;
cs->rp_offset++;
tcp_recved(pcb, 1);
}
}
next = cs->rp->next;
if(cs->rp->tot_len != cs->rp->len) {
pbuf_ref(next);
pbuf_free(cs->rp);
cs->rp = next;
cs->rp_offset = 0;
} else {
pbuf_free(cs->rp);
cs->rp = NULL;
}
}
}
static void kserver_err(void *arg, err_t err)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)arg;
cs_free(cs);
}
static struct tcp_pcb *listen_pcb;
static err_t kserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
struct kserver_connstate *cs;
cs = cs_new();
if(!cs)
return ERR_MEM;
tcp_accepted(listen_pcb);
tcp_arg(newpcb, cs);
tcp_recv(newpcb, kserver_recv);
tcp_err(newpcb, kserver_err);
return ERR_OK;
}
void kserver_init(void)
{
listen_pcb = tcp_new();
tcp_bind(listen_pcb, IP_ADDR_ANY, 1381);
listen_pcb = tcp_listen(listen_pcb);
tcp_accept(listen_pcb, kserver_accept);
}
extern struct tcp_pcb *tcp_active_pcbs;
void kserver_service(void)
{
struct tcp_pcb *pcb;
void *data;
int len, sndbuf;
/* Assume all active TCP PCBs with a non-NULL arg are our connections. */
pcb = tcp_active_pcbs;
while(pcb) {
if(pcb->callback_arg)
tcp_pcb_service(pcb->callback_arg, pcb);
pcb = pcb->next;
}
if(active_cs) {
session_poll(&data, &len);
if(len > 0) {
sndbuf = tcp_sndbuf(active_pcb);
if(len > sndbuf)
len = sndbuf;
tcp_write(active_pcb, data, len, 0);
session_ack_data(len);
}
if(len < 0)
kserver_close(active_cs, active_pcb);
}
}
#endif /* CSR_ETHMAC_BASE */

7
soc/runtime/kserver.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __KSERVER_H
#define __KSERVER_H
void kserver_init(void);
void kserver_service(void);
#endif /* __KSERVER_H */

View File

@ -21,12 +21,13 @@
#include <lwip/timers.h> #include <lwip/timers.h>
#endif #endif
#include "flash_storage.h"
#include "clock.h" #include "clock.h"
#include "test_mode.h" #include "test_mode.h"
#include "kserver.h"
#include "session.h" #include "session.h"
#ifdef CSR_ETHMAC_BASE #ifdef CSR_ETHMAC_BASE
unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
u32_t sys_now(void) u32_t sys_now(void)
{ {
@ -44,15 +45,69 @@ static void lwip_service(void)
} }
} }
unsigned char macadr[6];
static int hex2nib(int c)
{
if((c >= '0') && (c <= '9'))
return c - '0';
if((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
if((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
return -1;
}
static void init_macadr(void)
{
static const unsigned char default_macadr[6] = {0x10, 0xe2, 0xd5, 0x32, 0x50, 0x00};
char b[32];
char fs_macadr[6];
int i, r, s;
memcpy(macadr, default_macadr, 6);
r = fs_read("mac", b, sizeof(b) - 1, NULL);
if(r <= 0)
return;
b[r] = 0;
for(i=0;i<6;i++) {
r = hex2nib(b[3*i]);
s = hex2nib(b[3*i + 1]);
if((r < 0) || (s < 0))
return;
fs_macadr[i] = (r << 4) | s;
}
for(i=0;i<5;i++)
if(b[3*i + 2] != ':')
return;
memcpy(macadr, fs_macadr, 6);
}
static void fsip_or_default(struct ip4_addr *d, char *key, int i1, int i2, int i3, int i4)
{
int r;
char cp[32];
IP4_ADDR(d, i1, i2, i3, i4);
r = fs_read(key, cp, sizeof(cp) - 1, NULL);
if(r <= 0)
return;
cp[r] = 0;
if(!ip4addr_aton(cp, d))
return;
}
static void network_init(void) static void network_init(void)
{ {
struct ip4_addr local_ip; struct ip4_addr local_ip;
struct ip4_addr netmask; struct ip4_addr netmask;
struct ip4_addr gateway_ip; struct ip4_addr gateway_ip;
IP4_ADDR(&local_ip, 192, 168, 0, 42); init_macadr();
IP4_ADDR(&netmask, 255, 255, 255, 0); fsip_or_default(&local_ip, "ip", 192, 168, 0, 42);
IP4_ADDR(&gateway_ip, 192, 168, 0, 1); fsip_or_default(&netmask, "netmask", 255, 255, 255, 0);
fsip_or_default(&gateway_ip, "gateway", 192, 168, 0, 1);
lwip_init(); lwip_init();
@ -62,204 +117,9 @@ static void network_init(void)
netif_set_link_up(&netif); netif_set_link_up(&netif);
} }
struct kserver_connstate {
int magic_recognized;
struct pbuf *rp;
int rp_offset;
};
static struct kserver_connstate *cs_new(void)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)mem_malloc(sizeof(struct kserver_connstate));
if(!cs)
return NULL;
cs->magic_recognized = 0;
cs->rp = NULL;
cs->rp_offset = 0;
return cs;
}
static void cs_free(struct kserver_connstate *cs)
{
if(cs->rp)
pbuf_free(cs->rp);
mem_free(cs);
}
static const char kserver_magic[] = "ARTIQ coredev\n";
static int magic_ok(struct kserver_connstate *cs)
{
return cs->magic_recognized >= 14;
}
static struct kserver_connstate *active_cs;
static struct tcp_pcb *active_pcb;
static void kserver_close(struct kserver_connstate *cs, struct tcp_pcb *pcb)
{
if(cs == active_cs) {
session_end();
active_cs = NULL;
active_pcb = NULL;
}
/* lwip loves to call back with broken pointers. Prevent that. */
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_err(pcb, NULL);
cs_free(cs);
tcp_close(pcb);
}
static err_t kserver_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)arg;
if(p) {
if(cs->rp)
pbuf_cat(cs->rp, p);
else {
cs->rp = p;
cs->rp_offset = 0;
}
} else
kserver_close(cs, pcb);
return ERR_OK;
}
static err_t kserver_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
session_ack_mem(len);
return ERR_OK;
}
static void tcp_pcb_service(void *arg, struct tcp_pcb *pcb)
{
struct kserver_connstate *cs;
int remaining_in_pbuf;
char *rpp;
struct pbuf *next;
int r;
cs = (struct kserver_connstate *)arg;
while(cs->rp) {
remaining_in_pbuf = cs->rp->len - cs->rp_offset;
rpp = (char *)cs->rp->payload;
while(remaining_in_pbuf > 0) {
if(cs == active_cs) {
r = session_input(&rpp[cs->rp_offset], remaining_in_pbuf);
if(r > 0) {
tcp_recved(pcb, r);
cs->rp_offset += r;
remaining_in_pbuf -= r;
} else if(r == 0)
return;
else
kserver_close(cs, pcb);
} else {
if(rpp[cs->rp_offset] == kserver_magic[cs->magic_recognized]) {
cs->magic_recognized++;
if(magic_ok(cs)) {
if(active_cs)
kserver_close(active_cs, active_pcb);
session_start();
active_cs = cs;
active_pcb = pcb;
tcp_sent(pcb, kserver_sent);
}
} else {
kserver_close(cs, pcb);
return;
}
remaining_in_pbuf--;
cs->rp_offset++;
tcp_recved(pcb, 1);
}
}
next = cs->rp->next;
if(cs->rp->tot_len != cs->rp->len) {
pbuf_ref(next);
pbuf_free(cs->rp);
cs->rp = next;
cs->rp_offset = 0;
} else {
pbuf_free(cs->rp);
cs->rp = NULL;
}
}
}
static void kserver_err(void *arg, err_t err)
{
struct kserver_connstate *cs;
cs = (struct kserver_connstate *)arg;
cs_free(cs);
}
static struct tcp_pcb *listen_pcb;
static err_t kserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
struct kserver_connstate *cs;
cs = cs_new();
if(!cs)
return ERR_MEM;
tcp_accepted(listen_pcb);
tcp_arg(newpcb, cs);
tcp_recv(newpcb, kserver_recv);
tcp_err(newpcb, kserver_err);
return ERR_OK;
}
static void kserver_init(void)
{
listen_pcb = tcp_new();
tcp_bind(listen_pcb, IP_ADDR_ANY, 1381);
listen_pcb = tcp_listen(listen_pcb);
tcp_accept(listen_pcb, kserver_accept);
}
extern struct tcp_pcb *tcp_active_pcbs;
static void kserver_service(void)
{
struct tcp_pcb *pcb;
void *data;
int len, sndbuf;
/* Assume all active TCP PCBs with a non-NULL arg are our connections. */
pcb = tcp_active_pcbs;
while(pcb) {
if(pcb->callback_arg)
tcp_pcb_service(pcb->callback_arg, pcb);
pcb = pcb->next;
}
if(active_cs) {
session_poll(&data, &len);
if(len > 0) {
sndbuf = tcp_sndbuf(active_pcb);
if(len > sndbuf)
len = sndbuf;
tcp_write(active_pcb, data, len, 0);
session_ack_data(len);
}
if(len < 0)
kserver_close(active_cs, active_pcb);
}
}
static void regular_main(void) static void regular_main(void)
{ {
puts("Accepting sessions on Ethernet");
clock_init(); clock_init();
network_init(); network_init();
kserver_init(); kserver_init();
@ -317,6 +177,7 @@ static void serial_service(void)
static void regular_main(void) static void regular_main(void)
{ {
puts("Accepting sessions on serial link");
clock_init(); clock_init();
/* Open the session for the serial control. */ /* Open the session for the serial control. */
@ -369,12 +230,6 @@ int main(void)
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
#ifdef CSR_ETHMAC_BASE
puts("Accepting sessions on Ethernet");
#else
puts("Accepting sessions on serial link");
#endif
puts("Press 't' to enter test mode..."); puts("Press 't' to enter test mode...");
blink_led(); blink_led();