Compare commits
4 Commits
wip/irqopt
...
wip/mocom
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1f04d68a6 | ||
|
|
11d65682e4 | ||
|
|
d16ad10f17 | ||
|
|
89e52a426e |
33
app/mocom/app.c
Normal file
33
app/mocom/app.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <app.h>
|
||||
|
||||
extern void mocom_init(const struct app_descriptor *app);
|
||||
extern void mocom_entry(const struct app_descriptor *app, void *args);
|
||||
|
||||
APP_START(mocom)
|
||||
.init = mocom_init,
|
||||
.entry = mocom_entry,
|
||||
APP_END
|
||||
|
||||
|
||||
313
app/mocom/channel.cpp
Normal file
313
app/mocom/channel.cpp
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "channel.hpp"
|
||||
|
||||
#include <err.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <trace.h>
|
||||
#include <string.h>
|
||||
#include <rand.h>
|
||||
#include <target.h>
|
||||
#include <compiler.h>
|
||||
#include <ctype.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include "mux.hpp"
|
||||
#include "prot/mux.h"
|
||||
#include "cmd_handler/console.hpp"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
namespace mocom {
|
||||
|
||||
// base channel class
|
||||
|
||||
status_t channel::queue_tx(const void *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
if (m_tx_buf)
|
||||
return ERR_BUSY;
|
||||
|
||||
m_tx_buf = (const uint8_t *)buf;
|
||||
m_tx_len = len;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t channel::close()
|
||||
{
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// command channel
|
||||
|
||||
void control_channel::process_rx_packet(const uint8_t *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
const struct pmux_control_header *header = (const struct pmux_control_header *)buf;
|
||||
|
||||
if (len < sizeof(struct pmux_control_header))
|
||||
return;
|
||||
|
||||
switch (header->op) {
|
||||
default:
|
||||
case PMUX_CONTROL_NONE:
|
||||
break;
|
||||
case PMUX_CONTROL_CHANNEL_CLOSED:
|
||||
// they're telling us they got something on a closed channel
|
||||
// XXX ignore for now
|
||||
break;
|
||||
case PMUX_CONTROL_OPEN:
|
||||
// they're asking us to open a new channel
|
||||
PANIC_UNIMPLEMENTED;
|
||||
break;
|
||||
case PMUX_CONTROL_OPEN_COMMAND: {
|
||||
// they're asking us to open a command interpreter channel
|
||||
channel *c = new command_channel(m_mux, header->channel);
|
||||
if (!m_mux.add_channel(c)) {
|
||||
// already exists
|
||||
delete c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PMUX_CONTROL_CLOSE: {
|
||||
// they're asking us to close a channel
|
||||
channel *c = m_mux.find_channel(header->channel);
|
||||
if (c) {
|
||||
c->close();
|
||||
|
||||
m_mux.remove_channel(c);
|
||||
delete c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// command channel
|
||||
|
||||
static int tokenize_command(const char *inbuffer, size_t inbuflen, char *buffer, size_t buflen, char **args, size_t arg_count)
|
||||
{
|
||||
size_t inpos;
|
||||
size_t outpos;
|
||||
size_t arg;
|
||||
enum {
|
||||
INITIAL = 0,
|
||||
NEXT_FIELD,
|
||||
SPACE,
|
||||
IN_SPACE,
|
||||
TOKEN,
|
||||
IN_TOKEN,
|
||||
QUOTED_TOKEN,
|
||||
IN_QUOTED_TOKEN,
|
||||
} state;
|
||||
|
||||
inpos = 0;
|
||||
outpos = 0;
|
||||
arg = 0;
|
||||
state = INITIAL;
|
||||
|
||||
for (;;) {
|
||||
char c = inbuffer[inpos];
|
||||
|
||||
DEBUG_ASSERT(inpos < inbuflen);
|
||||
|
||||
LTRACEF_LEVEL(2, "c 0x%hhx state %d arg %d inpos %d pos %d\n", c, state, arg, inpos, outpos);
|
||||
|
||||
switch (state) {
|
||||
case INITIAL:
|
||||
case NEXT_FIELD:
|
||||
if (c == '\0')
|
||||
goto done;
|
||||
if (isspace(c))
|
||||
state = SPACE;
|
||||
else
|
||||
state = TOKEN;
|
||||
break;
|
||||
case SPACE:
|
||||
state = IN_SPACE;
|
||||
break;
|
||||
case IN_SPACE:
|
||||
if (c == '\0')
|
||||
goto done;
|
||||
if (!isspace(c)) {
|
||||
state = TOKEN;
|
||||
} else {
|
||||
inpos++; // consume the space
|
||||
if (inpos == inbuflen)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case TOKEN:
|
||||
// start of a token
|
||||
DEBUG_ASSERT(c != '\0');
|
||||
if (c == '"') {
|
||||
// start of a quoted token
|
||||
state = QUOTED_TOKEN;
|
||||
} else {
|
||||
// regular, unquoted token
|
||||
state = IN_TOKEN;
|
||||
args[arg] = &buffer[outpos];
|
||||
}
|
||||
break;
|
||||
case IN_TOKEN:
|
||||
if (c == '\0') {
|
||||
arg++;
|
||||
goto done;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
arg++;
|
||||
buffer[outpos] = 0;
|
||||
outpos++;
|
||||
/* are we out of tokens? */
|
||||
if (arg == arg_count)
|
||||
goto done;
|
||||
state = NEXT_FIELD;
|
||||
} else {
|
||||
buffer[outpos] = c;
|
||||
outpos++;
|
||||
inpos++;
|
||||
if (inpos == inbuflen) {
|
||||
arg++;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QUOTED_TOKEN:
|
||||
// start of a quoted token
|
||||
DEBUG_ASSERT(c == '"');
|
||||
|
||||
state = IN_QUOTED_TOKEN;
|
||||
args[arg] = &buffer[outpos];
|
||||
inpos++; // consume the quote
|
||||
if (inpos == inbuflen)
|
||||
goto done;
|
||||
break;
|
||||
case IN_QUOTED_TOKEN:
|
||||
if (c == '\0') {
|
||||
arg++;
|
||||
goto done;
|
||||
}
|
||||
if (c == '"') {
|
||||
arg++;
|
||||
buffer[outpos] = 0;
|
||||
outpos++;
|
||||
/* are we out of tokens? */
|
||||
if (arg == arg_count)
|
||||
goto done;
|
||||
|
||||
state = NEXT_FIELD;
|
||||
}
|
||||
buffer[outpos] = c;
|
||||
outpos++;
|
||||
inpos++;
|
||||
if (inpos == inbuflen) {
|
||||
arg++;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* are we at the end of the output buffer? */
|
||||
if (outpos == buflen - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
buffer[outpos] = 0;
|
||||
return arg;
|
||||
}
|
||||
|
||||
void command_channel::process_rx_packet(const uint8_t *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
//hexdump8_ex(buf, len, 0);
|
||||
|
||||
if (m_state == STATE_INITIAL) {
|
||||
// try to parse the incoming command
|
||||
|
||||
char outbuf[128];
|
||||
char *tokens[16];
|
||||
int count = tokenize_command((const char *)buf, len, outbuf, sizeof(outbuf), tokens, countof(tokens));
|
||||
|
||||
LTRACEF("command word count %d\n", count);
|
||||
|
||||
if (count >= 2 && !strcmp(tokens[0], "open") && !strcmp(tokens[1], "console")) {
|
||||
// the only command we understand right now
|
||||
DEBUG_ASSERT(!m_handler);
|
||||
|
||||
cmd_handler::console *c = new cmd_handler::console(*this);
|
||||
if (c->Init() < NO_ERROR) {
|
||||
delete c;
|
||||
goto error;
|
||||
}
|
||||
m_handler = c;
|
||||
|
||||
queue_tx(strdup("ok 0\n"), strlen("ok 0\n"));
|
||||
m_state = STATE_ESTABLISHED;
|
||||
} else {
|
||||
error:
|
||||
// everything else is unrecognized
|
||||
snprintf(outbuf, sizeof(outbuf), "err %d %s\n", -1, "unrecognized command");
|
||||
LTRACEF("returning '%s\n", outbuf);
|
||||
queue_tx(strdup(outbuf), strlen(outbuf));
|
||||
}
|
||||
} else if (m_state == STATE_ESTABLISHED) {
|
||||
DEBUG_ASSERT(m_handler);
|
||||
|
||||
m_handler->process_rx_packet(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void command_channel::tx_complete()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
channel::tx_complete();
|
||||
|
||||
if (m_handler)
|
||||
m_handler->tx_complete();
|
||||
}
|
||||
|
||||
status_t command_channel::close()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
if (m_handler)
|
||||
m_handler->close();
|
||||
|
||||
return channel::close();
|
||||
}
|
||||
|
||||
command_channel::~command_channel()
|
||||
{
|
||||
if (m_handler)
|
||||
delete m_handler;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
100
app/mocom/channel.hpp
Normal file
100
app/mocom/channel.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <list.h>
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
namespace mocom {
|
||||
|
||||
class mux;
|
||||
|
||||
class channel : lk::nocopy {
|
||||
public:
|
||||
channel(mux &m, uint32_t num) : m_mux(m), m_num(num) {}
|
||||
virtual ~channel() {}
|
||||
|
||||
virtual void process_rx_packet(const uint8_t *buf, size_t len) = 0;
|
||||
virtual status_t close();
|
||||
|
||||
uint32_t get_num() const { return m_num; }
|
||||
|
||||
virtual status_t queue_tx(const void *buf, size_t len);
|
||||
virtual void tx_complete() { m_tx_buf = nullptr; m_tx_len = 0; }
|
||||
|
||||
protected:
|
||||
mux &m_mux;
|
||||
|
||||
uint32_t m_num;
|
||||
|
||||
// rx stuff
|
||||
uint32_t m_rx_sequence = 0;
|
||||
uint32_t m_pending_ack_sequence = 0;
|
||||
bool m_pending_ack = false;
|
||||
|
||||
// tx stuff
|
||||
uint32_t m_tx_sequence = 0;
|
||||
uint32_t m_acked_tx_sequence = 0;
|
||||
const uint8_t *m_tx_buf = nullptr;
|
||||
size_t m_tx_len = 0;
|
||||
|
||||
// list of us in the mux class
|
||||
friend class mux;
|
||||
struct list_node m_list_node = LIST_INITIAL_CLEARED_VALUE;
|
||||
};
|
||||
|
||||
class control_channel : public channel {
|
||||
public:
|
||||
control_channel(mux &m, uint32_t num) : channel(m, num) {}
|
||||
virtual ~control_channel() {}
|
||||
|
||||
virtual void process_rx_packet(const uint8_t *buf, size_t len) override;
|
||||
};
|
||||
|
||||
namespace cmd_handler {
|
||||
class handler;
|
||||
}
|
||||
|
||||
class command_channel : public channel {
|
||||
public:
|
||||
command_channel(mux &m, uint32_t num) : channel(m, num) {}
|
||||
virtual ~command_channel();
|
||||
|
||||
virtual void process_rx_packet(const uint8_t *buf, size_t len) override;
|
||||
virtual void tx_complete() override;
|
||||
virtual status_t close() override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
STATE_INITIAL,
|
||||
STATE_ESTABLISHED
|
||||
} m_state = STATE_INITIAL;
|
||||
|
||||
// specialized handler to handle the command
|
||||
cmd_handler::handler *m_handler = nullptr;
|
||||
};
|
||||
|
||||
} // namespace mocom
|
||||
|
||||
137
app/mocom/cmd_handler/console.cpp
Normal file
137
app/mocom/cmd_handler/console.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "console.hpp"
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <trace.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <../prot/packet_struct.h>
|
||||
#include <../mocom_app.hpp>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
namespace mocom {
|
||||
namespace cmd_handler {
|
||||
|
||||
console::console(command_channel &c)
|
||||
: handler(c)
|
||||
{
|
||||
}
|
||||
|
||||
console::~console()
|
||||
{
|
||||
the_app->unregister_worker(m_worker);
|
||||
if (m_registered)
|
||||
unregister_print_callback(&m_cb);
|
||||
}
|
||||
|
||||
void console::debug_console_callback(print_callback_t *cb, const char *str, size_t len)
|
||||
{
|
||||
cbuf_write(&m_outbuf, str, len, false);
|
||||
|
||||
the_app->signal_irq();
|
||||
}
|
||||
|
||||
lk_time_t console::work()
|
||||
{
|
||||
//LTRACE_ENTRY;
|
||||
|
||||
// see if we need to output anything
|
||||
if (!is_tx_pending() && cbuf_space_used(&m_outbuf) > 0) {
|
||||
// grab a pointer directly into the cbuf and send it
|
||||
iovec_t iov[2];
|
||||
cbuf_peek(&m_outbuf, iov);
|
||||
|
||||
DEBUG_ASSERT(iov[0].iov_len > 0);
|
||||
|
||||
size_t _len = iov[0].iov_len;
|
||||
send_stdout_data((const char *)iov[0].iov_base, _len);
|
||||
|
||||
// consume the data we sent from the cbuf
|
||||
cbuf_read(&m_outbuf, NULL, _len, false);
|
||||
|
||||
// make sure the worker loops around immediately at least once to queue data
|
||||
return 0;
|
||||
} else {
|
||||
return INFINITE_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void console::process_rx_packet(const uint8_t *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
const struct packet_header *header = (const struct packet_header *)buf;
|
||||
|
||||
if (len < sizeof(struct packet_header))
|
||||
return; // XXX shoudl probably close the channel
|
||||
if (header->magic != PACKET_HEADER_MAGIC)
|
||||
return;
|
||||
if (header->version != PACKET_HEADER_VERSION)
|
||||
return;
|
||||
|
||||
if (header->type == PACKET_HEADER_TYPE_DATA) {
|
||||
const uint8_t *data = (const uint8_t *)header->data;
|
||||
hexdump8_ex(data, header->size, 0);
|
||||
|
||||
// feed it into the input queue (which doesn't exist right now)
|
||||
}
|
||||
}
|
||||
|
||||
void console::tx_complete()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
handler::tx_complete();
|
||||
|
||||
if (cbuf_space_used(&m_outbuf) > 0) {
|
||||
the_app->signal();
|
||||
}
|
||||
}
|
||||
|
||||
status_t console::Init()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
// initialize the outgoing circular buffer
|
||||
cbuf_initialize_etc(&m_outbuf, OUTBUF_LEN, &m_outbuf_buf);
|
||||
|
||||
// register a worker callback from the main mocom app
|
||||
m_worker.context = this;
|
||||
m_worker.work = &_work;
|
||||
the_app->register_worker(m_worker);
|
||||
|
||||
// register for a debug console handler
|
||||
m_cb.context = this;
|
||||
m_cb.print = &_debug_console_callback;
|
||||
register_print_callback(&m_cb);
|
||||
m_registered = true;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
75
app/mocom/cmd_handler/console.hpp
Normal file
75
app/mocom/cmd_handler/console.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <debug.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
#include "handler.hpp"
|
||||
#include "../mocom_app.hpp"
|
||||
|
||||
namespace mocom {
|
||||
namespace cmd_handler {
|
||||
|
||||
class console : public handler {
|
||||
public:
|
||||
console(command_channel &c);
|
||||
virtual ~console();
|
||||
|
||||
virtual status_t Init() override;
|
||||
virtual void process_rx_packet(const uint8_t *buf, size_t len) override;
|
||||
virtual void tx_complete() override;
|
||||
|
||||
private:
|
||||
// main worker callback
|
||||
lk_time_t work();
|
||||
static lk_time_t _work(void *context) { return ((console *)context)->work(); }
|
||||
|
||||
mocom_app::worker_callback m_worker;
|
||||
|
||||
// debug console callback
|
||||
void debug_console_callback(print_callback_t *cb, const char *str, size_t len);
|
||||
static void _debug_console_callback(print_callback_t *cb, const char *str, size_t len) {
|
||||
((console *)cb->context)->debug_console_callback(cb, str, len);
|
||||
}
|
||||
|
||||
bool m_registered = false;
|
||||
print_callback_t m_cb;
|
||||
|
||||
// circular buffer to hold outgoing print data
|
||||
cbuf_t m_outbuf;
|
||||
static const size_t OUTBUF_LEN = 1024;
|
||||
char m_outbuf_buf[OUTBUF_LEN];
|
||||
|
||||
// state of tx
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
90
app/mocom/cmd_handler/handler.cpp
Normal file
90
app/mocom/cmd_handler/handler.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "console.hpp"
|
||||
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <trace.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <../prot/packet_struct.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
namespace mocom {
|
||||
namespace cmd_handler {
|
||||
|
||||
handler::handler(command_channel &c)
|
||||
: m_cc(c)
|
||||
{
|
||||
}
|
||||
|
||||
handler::~handler()
|
||||
{
|
||||
DEBUG_ASSERT(!m_outbuf);
|
||||
}
|
||||
|
||||
status_t handler::send_stdout_data(const char *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
if (m_outbuf)
|
||||
return ERR_NOT_READY;
|
||||
|
||||
/// XXX remove
|
||||
m_outbuf = new char[len + sizeof(struct packet_header)];
|
||||
if (!m_outbuf)
|
||||
return ERR_NO_MEMORY;
|
||||
|
||||
struct packet_header *header = (struct packet_header *)m_outbuf;
|
||||
header->magic = PACKET_HEADER_MAGIC;
|
||||
header->version = PACKET_HEADER_VERSION;
|
||||
header->type = PACKET_HEADER_TYPE_DATA;
|
||||
header->size = len;
|
||||
|
||||
memcpy(header->data, buf, len);
|
||||
|
||||
return m_cc.queue_tx(m_outbuf, sizeof(struct packet_header) + len);
|
||||
}
|
||||
|
||||
void handler::tx_complete()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
if (m_outbuf) {
|
||||
delete m_outbuf;
|
||||
m_outbuf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void handler::close()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
tx_complete();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
57
app/mocom/cmd_handler/handler.hpp
Normal file
57
app/mocom/cmd_handler/handler.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <list.h>
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
#include "../channel.hpp"
|
||||
|
||||
namespace mocom {
|
||||
namespace cmd_handler {
|
||||
|
||||
class handler : lk::nocopy {
|
||||
public:
|
||||
handler(command_channel &c);
|
||||
virtual ~handler();
|
||||
|
||||
virtual status_t Init() = 0;
|
||||
virtual void process_rx_packet(const uint8_t *buf, size_t len) = 0;
|
||||
virtual void close();
|
||||
virtual void tx_complete();
|
||||
|
||||
status_t send_stdout_data(const char *buf, size_t len);
|
||||
|
||||
bool is_tx_pending() const { return m_outbuf; }
|
||||
|
||||
protected:
|
||||
command_channel &m_cc;
|
||||
|
||||
char *m_outbuf = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
32
app/mocom/include/app/mocom.h
Normal file
32
app/mocom/include/app/mocom.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <compiler.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
|
||||
__END_CDECLS
|
||||
|
||||
39
app/mocom/include/app/mocom/usb.h
Normal file
39
app/mocom/include/app/mocom/usb.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_DEV_USB
|
||||
|
||||
#include <compiler.h>
|
||||
#include <app/mocom.h>
|
||||
#include <sys/types.h>
|
||||
#include <dev/usbc.h>
|
||||
|
||||
__BEGIN_CDECLS
|
||||
|
||||
status_t mocom_configure_usb_endpoints(uint interface_num, ep_t inep, ep_t outep);
|
||||
|
||||
__END_CDECLS
|
||||
|
||||
#endif
|
||||
143
app/mocom/mocom.cpp
Normal file
143
app/mocom/mocom.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "mocom_app.hpp"
|
||||
#include <app/mocom.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <trace.h>
|
||||
#include <target.h>
|
||||
#include <compiler.h>
|
||||
#include <app.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/mutex.h>
|
||||
|
||||
#include "transport.hpp"
|
||||
#include "usb.hpp"
|
||||
#include <lib/cpputils/autolocker.hpp>
|
||||
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
namespace mocom {
|
||||
|
||||
mocom_app *the_app;
|
||||
|
||||
mocom_app::mocom_app(transport &t)
|
||||
: m_transport(t),
|
||||
m_mux(m_transport)
|
||||
{
|
||||
mutex_init(&m_workers_mutex);
|
||||
}
|
||||
|
||||
mocom_app::~mocom_app()
|
||||
{
|
||||
mutex_destroy(&m_workers_mutex);
|
||||
}
|
||||
|
||||
status_t mocom_app::worker()
|
||||
{
|
||||
for (;;) {
|
||||
lk_time_t t = INFINITE_TIME;
|
||||
|
||||
// call all of the workers, returning the shortest time returned
|
||||
|
||||
// let the transport layer do some work
|
||||
lk_time_t temp = m_transport.do_work();
|
||||
if (temp < t)
|
||||
t = temp;
|
||||
|
||||
// call all of the registered workers
|
||||
mutex_acquire(&m_workers_mutex);
|
||||
worker_callback *cb;
|
||||
list_for_every_entry(&m_workers, cb, worker_callback, node) {
|
||||
temp = cb->work(cb->context);
|
||||
if (temp < t)
|
||||
t = temp;
|
||||
}
|
||||
mutex_release(&m_workers_mutex);
|
||||
|
||||
// wait a cycle
|
||||
if (t > 0) {
|
||||
//LTRACEF("waiting %u msec\n", t);
|
||||
event_wait_timeout(&m_event, t);
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void mocom_app::register_worker(worker_callback &cb)
|
||||
{
|
||||
mutex_acquire(&m_workers_mutex);
|
||||
list_add_head(&m_workers, &cb.node);
|
||||
mutex_release(&m_workers_mutex);
|
||||
}
|
||||
|
||||
void mocom_app::unregister_worker(worker_callback &cb)
|
||||
{
|
||||
mutex_acquire(&m_workers_mutex);
|
||||
list_delete(&cb.node);
|
||||
mutex_release(&m_workers_mutex);
|
||||
}
|
||||
|
||||
status_t mocom_app::init()
|
||||
{
|
||||
event_init(&m_event, false, EVENT_FLAG_AUTOUNSIGNAL);
|
||||
|
||||
m_transport.set_mux(&m_mux);
|
||||
m_transport.init();
|
||||
m_mux.init();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
extern "C" void mocom_init(const struct app_descriptor *app)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void mocom_entry(const struct app_descriptor *, void *)
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
// construct a transport for us to talk over
|
||||
#if WITH_DEV_USB
|
||||
transport *t = create_usb_transport();
|
||||
#endif
|
||||
|
||||
// construct the main mocom app
|
||||
mocom_app app(*t);
|
||||
|
||||
// set a singleton pointer to it
|
||||
the_app = &app;
|
||||
|
||||
app.init();
|
||||
|
||||
// bump ourselves to high priority
|
||||
thread_set_priority(HIGH_PRIORITY);
|
||||
|
||||
app.worker();
|
||||
}
|
||||
|
||||
} // namespace mocom
|
||||
|
||||
76
app/mocom/mocom_app.hpp
Normal file
76
app/mocom/mocom_app.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <list.h>
|
||||
#include <sys/types.h>
|
||||
#include <kernel/event.h>
|
||||
#include <kernel/mutex.h>
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
#include "transport.hpp"
|
||||
#include "mux.hpp"
|
||||
|
||||
namespace mocom {
|
||||
|
||||
class mocom_app : lk::nocopy {
|
||||
public:
|
||||
mocom_app(transport &);
|
||||
~mocom_app();
|
||||
|
||||
status_t init();
|
||||
|
||||
status_t worker();
|
||||
|
||||
// allow registering a worker routine to be run in the main thread context
|
||||
struct worker_callback {
|
||||
struct list_node node;
|
||||
void *context;
|
||||
lk_time_t (*work)(void *context);
|
||||
};
|
||||
void register_worker(worker_callback &cb);
|
||||
void unregister_worker(worker_callback &cb);
|
||||
|
||||
// signal that the workers should cycle through
|
||||
void signal() { event_signal(&m_event, true); }
|
||||
void signal_irq() { event_signal(&m_event, false); }
|
||||
|
||||
private:
|
||||
// transport
|
||||
transport &m_transport;
|
||||
|
||||
// mux layer
|
||||
mux m_mux;
|
||||
|
||||
// main app event
|
||||
event_t m_event;
|
||||
|
||||
// mutex to protect list of workers.
|
||||
mutex_t m_workers_mutex;
|
||||
|
||||
struct list_node m_workers = LIST_INITIAL_VALUE(m_workers);
|
||||
};
|
||||
|
||||
// the singleton app
|
||||
extern mocom_app *the_app;
|
||||
|
||||
}
|
||||
249
app/mocom/mux.cpp
Normal file
249
app/mocom/mux.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "mux.hpp"
|
||||
#include "prot/mux.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <trace.h>
|
||||
#include <string.h>
|
||||
#include <rand.h>
|
||||
#include <target.h>
|
||||
#include <compiler.h>
|
||||
#include <platform.h>
|
||||
#include <lib/cksum.h>
|
||||
|
||||
#include "channel.hpp"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
#define TRACE_PACKETS 0
|
||||
|
||||
namespace mocom {
|
||||
|
||||
static const char *control_op_to_string(uint32_t op)
|
||||
{
|
||||
switch (op) {
|
||||
case PMUX_CONTROL_NONE:
|
||||
return "none";
|
||||
case PMUX_CONTROL_CHANNEL_CLOSED:
|
||||
return "closed";
|
||||
case PMUX_CONTROL_OPEN:
|
||||
return "open";
|
||||
case PMUX_CONTROL_OPEN_COMMAND:
|
||||
return "openc";
|
||||
case PMUX_CONTROL_CLOSE:
|
||||
return "close";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#define PMUX_RX 0
|
||||
#define PMUX_TX 1
|
||||
|
||||
static void dump_packet(const void *buf, size_t len, int txrx)
|
||||
{
|
||||
#define TXRX ((txrx == PMUX_TX) ? "TX" : "RX")
|
||||
|
||||
if (!buf || len == 0) {
|
||||
// printf("%s NULL\n", TXRX);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pmux_header *header = (struct pmux_header *)buf;
|
||||
|
||||
if ((header->flags & PMUX_FLAG_ACK)) {
|
||||
printf("%s ACK c %-6d seq %-8d len %-8d tlen %-8d\n",
|
||||
TXRX, header->channel, header->sequence, header->payload_len, header->total_len);
|
||||
} else {
|
||||
if (header->channel == PMUX_CHANNEL_CONTROL) {
|
||||
struct pmux_control_header *control = (struct pmux_control_header *)header->data;
|
||||
printf("%s DATA c %-6d seq %-8d len %-8d tlen %-8d CONTROL op %d %6s c %-6d len %-6d\n", TXRX,
|
||||
header->channel, header->sequence, header->payload_len, header->total_len,
|
||||
control->op, control_op_to_string(control->op), control->channel, control->len);
|
||||
} else {
|
||||
printf("%s DATA c %-6d seq %-8d len %-8d tlen %-8d crc %08x\n", TXRX,
|
||||
header->channel, header->sequence, header->payload_len, header->total_len, header->crc);
|
||||
}
|
||||
}
|
||||
#undef TXRX
|
||||
}
|
||||
|
||||
void mux::init()
|
||||
{
|
||||
// create a default control channel
|
||||
control_channel *cc = new control_channel(*this, PMUX_CHANNEL_CONTROL);
|
||||
add_channel(cc);
|
||||
}
|
||||
|
||||
channel *mux::find_channel(uint32_t num)
|
||||
{
|
||||
channel *c;
|
||||
list_for_every_entry(&m_channel_list, c, channel, m_list_node) {
|
||||
if (c->get_num() == num)
|
||||
return c;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool mux::add_channel(channel *c)
|
||||
{
|
||||
if (find_channel(c->get_num()))
|
||||
return false;
|
||||
|
||||
list_add_head(&m_channel_list, &c->m_list_node);
|
||||
return true;
|
||||
}
|
||||
|
||||
void mux::remove_channel(channel *c)
|
||||
{
|
||||
list_delete(&c->m_list_node);
|
||||
}
|
||||
|
||||
void mux::set_online(bool online)
|
||||
{
|
||||
LTRACEF("online %u\n", online);
|
||||
}
|
||||
|
||||
void mux::process_rx_packet(const uint8_t *buf, size_t len)
|
||||
{
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
const struct pmux_header *header = (const struct pmux_header *)buf;
|
||||
|
||||
if (len < sizeof(struct pmux_header))
|
||||
return;
|
||||
if (header->magic != PMUX_MAGIC)
|
||||
return;
|
||||
if (header->version != PMUX_VERSION)
|
||||
return;
|
||||
|
||||
#if TRACE_PACKETS
|
||||
dump_packet(buf, len, PMUX_RX);
|
||||
#endif
|
||||
|
||||
channel *c = find_channel(header->channel);
|
||||
if (c) {
|
||||
if (header->flags & PMUX_FLAG_ACK) {
|
||||
// this is an ack for us
|
||||
if (header->sequence > c->m_acked_tx_sequence && header->sequence <= c->m_tx_sequence) {
|
||||
c->m_acked_tx_sequence = header->sequence;
|
||||
if (c->m_acked_tx_sequence == c->m_tx_sequence) {
|
||||
// we are completely acked, so we can kill the tx queue
|
||||
c->tx_complete();
|
||||
}
|
||||
} else {
|
||||
// ack out of sequence
|
||||
}
|
||||
} else {
|
||||
// we have received data
|
||||
if (header->sequence == (c->m_rx_sequence + 1)) {
|
||||
// in sequence from the other side
|
||||
c->process_rx_packet((uint8_t *)(header + 1), len - sizeof(*header));
|
||||
c->m_rx_sequence = header->sequence;
|
||||
c->m_pending_ack_sequence = header->sequence;
|
||||
c->m_pending_ack = true;
|
||||
} else if (header->sequence <= c->m_rx_sequence) {
|
||||
// they are retransmitting for some reason, re-ack it
|
||||
c->m_pending_ack_sequence = c->m_rx_sequence;
|
||||
c->m_pending_ack = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TRACEF("packet for non open channel %u\n", header->channel);
|
||||
// XXX send CONTROL_CLOSED
|
||||
PANIC_UNIMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t mux::prepare_tx_packet(uint8_t *buf, size_t len)
|
||||
{
|
||||
//LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
// see if any channels need an ack
|
||||
channel *c;
|
||||
list_for_every_entry(&m_channel_list, c, channel, m_list_node) {
|
||||
if (c->m_pending_ack) {
|
||||
c->m_pending_ack = false;
|
||||
|
||||
struct pmux_header *header = (struct pmux_header *)buf;
|
||||
|
||||
header->magic = PMUX_MAGIC;
|
||||
header->version = PMUX_VERSION;
|
||||
header->flags = PMUX_FLAG_ACK;
|
||||
header->channel = c->get_num();
|
||||
header->sequence = c->m_pending_ack_sequence;
|
||||
header->payload_len = 0;
|
||||
header->total_len = sizeof(struct pmux_header);
|
||||
|
||||
#if TRACE_PACKETS
|
||||
dump_packet(buf, header->total_len, true);
|
||||
#endif
|
||||
|
||||
LTRACEF("acking channel %u\n", c->get_num());
|
||||
return header->total_len;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX handle retransmits
|
||||
|
||||
|
||||
// see if any channels have data to send
|
||||
list_for_every_entry(&m_channel_list, c, channel, m_list_node) {
|
||||
if (c->m_tx_buf && c->m_acked_tx_sequence == c->m_tx_sequence) {
|
||||
// we have pending data and the other side has fully acked us
|
||||
struct pmux_header *header = (struct pmux_header *)buf;
|
||||
|
||||
size_t data_len = MIN(c->m_tx_len, len - sizeof(struct pmux_header));
|
||||
|
||||
header->magic = PMUX_MAGIC;
|
||||
header->version = PMUX_VERSION;
|
||||
header->flags = 0;
|
||||
header->channel = c->get_num();
|
||||
header->sequence = ++c->m_tx_sequence;
|
||||
header->payload_len = data_len;
|
||||
header->total_len = sizeof(struct pmux_header) + data_len;
|
||||
memcpy(header->data, c->m_tx_buf, data_len);
|
||||
header->crc = adler32(1, header->data, header->payload_len);
|
||||
|
||||
// XXX for now can only consume the entire queued tx len
|
||||
DEBUG_ASSERT(data_len == c->m_tx_len);
|
||||
|
||||
#if TRACE_PACKETS
|
||||
dump_packet(buf, header->total_len, true);
|
||||
#endif
|
||||
|
||||
LTRACEF("sending %u bytes on channel %u\n", header->payload_len, c->get_num());
|
||||
return header->total_len;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
59
app/mocom/mux.hpp
Normal file
59
app/mocom/mux.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <list.h>
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
namespace mocom {
|
||||
|
||||
class transport;
|
||||
class channel;
|
||||
|
||||
class mux : lk::nocopy {
|
||||
public:
|
||||
mux(transport &transport) : m_transport(transport) {}
|
||||
~mux() {}
|
||||
|
||||
void init();
|
||||
void set_online(bool online);
|
||||
void process_rx_packet(const uint8_t *buf, size_t len);
|
||||
ssize_t prepare_tx_packet(uint8_t *buf, size_t len);
|
||||
|
||||
private:
|
||||
// handle to transport
|
||||
transport &m_transport;
|
||||
|
||||
channel *find_channel(uint32_t num);
|
||||
bool add_channel(channel *c);
|
||||
void remove_channel(channel *c);
|
||||
|
||||
struct list_node m_channel_list = LIST_INITIAL_VALUE(m_channel_list);
|
||||
|
||||
friend class control_channel;
|
||||
};
|
||||
|
||||
} // namespace mocom
|
||||
|
||||
76
app/mocom/prot/mux.h
Normal file
76
app/mocom/prot/mux.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* @@@LICENSE
|
||||
*
|
||||
* Copyright (c) 2008-2013 LG Electronics, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LICENSE@@@ */
|
||||
|
||||
#ifndef __LIB_PMUX_MUX_H
|
||||
#define __LIB_PMUX_MUX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* pmux definitions */
|
||||
#define PMUX_MAGIC 0x706d7578 /* 'pmux' */
|
||||
#define PMUX_VERSION 3 /* current version */
|
||||
|
||||
#define PMUX_FLAG_ACK 1 /* this packet is an ack */
|
||||
|
||||
struct pmux_header {
|
||||
uint32_t magic;
|
||||
uint8_t version;
|
||||
uint8_t _pad;
|
||||
uint16_t flags;
|
||||
uint32_t channel;
|
||||
uint32_t sequence;
|
||||
uint32_t payload_len;
|
||||
uint32_t total_len;
|
||||
|
||||
uint32_t crc;
|
||||
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/* control messages */
|
||||
enum pmux_control_message_op {
|
||||
PMUX_CONTROL_NONE = 0,
|
||||
PMUX_CONTROL_CHANNEL_CLOSED,
|
||||
PMUX_CONTROL_OPEN,
|
||||
PMUX_CONTROL_OPEN_COMMAND, /* open a channel with a command interpreter */
|
||||
PMUX_CONTROL_CLOSE,
|
||||
};
|
||||
|
||||
struct pmux_control_header {
|
||||
uint32_t op;
|
||||
uint32_t channel;
|
||||
uint32_t len;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
enum pmux_channel_num {
|
||||
PMUX_CHANNEL_NULL, /* non channel, for when you actually dont want to send data */
|
||||
PMUX_CHANNEL_CONTROL, /* special control commands go over this channel */
|
||||
|
||||
PMUX_CHANNEL_CMDSERVICE = 0x50, /* device service commands go over this channel */
|
||||
|
||||
PMUX_CHANNEL_MAX_FIXED = 0xfff,
|
||||
PMUX_CHANNEL_HOST_BASE = 0x1000,
|
||||
PMUX_CHANNEL_MAX_HOST = 0x7fffffff,
|
||||
PMUX_CHANNEL_DEVICE_BASE = 0x80000000,
|
||||
PMUX_CHANNEL_MAX_DEVICE = 0xffffffff
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
64
app/mocom/prot/packet_struct.h
Normal file
64
app/mocom/prot/packet_struct.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* @@@LICENSE
|
||||
*
|
||||
* Copyright (c) 2008-2013 LG Electronics, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LICENSE@@@ */
|
||||
|
||||
#ifndef __PACKET_STRUCT_H
|
||||
#define __PACKET_STRUCT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* on the wire packet data structure */
|
||||
#define PACKET_HEADER_MAGIC 0xDECAFBAD
|
||||
#define PACKET_HEADER_VERSION 1
|
||||
|
||||
/* packet types */
|
||||
#define PACKET_HEADER_TYPE_DATA 0
|
||||
#define PACKET_HEADER_TYPE_ERR 1
|
||||
#define PACKET_HEADER_TYPE_OOB 2
|
||||
|
||||
struct packet_header {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/* OOB messages */
|
||||
#define PACKET_OOB_EOF 0
|
||||
#define PACKET_OOB_SIGNAL 1
|
||||
#define PACKET_OOB_RETURN 2
|
||||
#define PACKET_OOB_RESIZE 3
|
||||
|
||||
/* data payload for OOB messages */
|
||||
struct packet_oob_msg {
|
||||
uint32_t message;
|
||||
union {
|
||||
uint32_t signo;
|
||||
int32_t returncode;
|
||||
int32_t fileno; /* stdin, stdout, stderr */
|
||||
struct {
|
||||
uint32_t rows;
|
||||
uint32_t cols;
|
||||
} resize;
|
||||
uint32_t pad[4]; /* pad it out to 16 bytes, for future expansion*/
|
||||
} data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
72
app/mocom/prot/transport_usb_struct.h
Normal file
72
app/mocom/prot/transport_usb_struct.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* @@@LICENSE
|
||||
*
|
||||
* Copyright (c) 2008-2013 LG Electronics, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* LICENSE@@@ */
|
||||
|
||||
#ifndef __TRANSPORT_USB_STRUCT_H
|
||||
#define __TRANSPORT_USB_STRUCT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define USBLL_MAGIC 0x7573626c // 'usbl'
|
||||
#define USBLL_VERSION 1
|
||||
|
||||
struct usbll_header {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t txid;
|
||||
uint32_t rxid;
|
||||
uint32_t command;
|
||||
};
|
||||
/*
|
||||
* Sync header definition
|
||||
* It is possible to send accross more data than sizeof(usbll_syn_header):
|
||||
* data_offset: offset of string data (calculated starting from usbll_syn_header)
|
||||
* data_length: sizeof string data (including \0 string terminator)
|
||||
*/
|
||||
struct usbll_syn_header {
|
||||
uint8_t nduid[40];
|
||||
uint32_t mtu;
|
||||
|
||||
/* added later, short header means this is default */
|
||||
uint32_t heartbeat_interval;
|
||||
uint32_t timeout;
|
||||
|
||||
/* adding support of extra data (assumed string) after syn header*/
|
||||
uint32_t data_offset;
|
||||
uint32_t data_length;
|
||||
};
|
||||
|
||||
enum usbll_command {
|
||||
usbll_null = 0, // an ack-like packet to detect spurious syns
|
||||
usbll_rst,
|
||||
usbll_syn,
|
||||
usbll_data,
|
||||
};
|
||||
|
||||
/*
|
||||
* Recover token structure definition
|
||||
* USBLL recovery token structure consist of txid, rxid, magic, version (see protocol header)
|
||||
*/
|
||||
typedef struct usbll_recovery_token {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t txid;
|
||||
uint32_t rxid;
|
||||
} usbll_recovery_token_t;
|
||||
|
||||
#endif
|
||||
|
||||
23
app/mocom/rules.mk
Normal file
23
app/mocom/rules.mk
Normal file
@@ -0,0 +1,23 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_DEPS := \
|
||||
lib/cbuf \
|
||||
lib/cksum \
|
||||
lib/cpputils
|
||||
|
||||
MODULE_CPPFLAGS := -std=c++11
|
||||
MODULE_CPPFLAGS += -Wno-invalid-offsetof # XXX this may be a terrible idea
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/app.c \
|
||||
$(LOCAL_DIR)/channel.cpp \
|
||||
$(LOCAL_DIR)/mocom.cpp \
|
||||
$(LOCAL_DIR)/mux.cpp \
|
||||
$(LOCAL_DIR)/usb.cpp \
|
||||
\
|
||||
$(LOCAL_DIR)/cmd_handler/console.cpp \
|
||||
$(LOCAL_DIR)/cmd_handler/handler.cpp \
|
||||
|
||||
include make/module.mk
|
||||
46
app/mocom/transport.hpp
Normal file
46
app/mocom/transport.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
namespace mocom {
|
||||
|
||||
class mux;
|
||||
|
||||
class transport : lk::nocopy {
|
||||
public:
|
||||
transport() {}
|
||||
virtual ~transport() {}
|
||||
|
||||
// virtual api
|
||||
virtual status_t init() = 0;
|
||||
virtual lk_time_t do_work() = 0;
|
||||
|
||||
void set_mux(mux *m) { m_mux = m; }
|
||||
|
||||
protected:
|
||||
mux *m_mux = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
404
app/mocom/usb.cpp
Normal file
404
app/mocom/usb.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "usb.hpp"
|
||||
#include "prot/transport_usb_struct.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <trace.h>
|
||||
#include <string.h>
|
||||
#include <rand.h>
|
||||
#include <target.h>
|
||||
#include <compiler.h>
|
||||
#include <platform.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/spinlock.h>
|
||||
#include <dev/usb.h>
|
||||
#include <dev/usbc.h>
|
||||
#include <app/mocom/usb.h>
|
||||
|
||||
#include "mux.hpp"
|
||||
#include "mocom_app.hpp"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
#define TRACE_PACKETS 0
|
||||
|
||||
namespace mocom {
|
||||
|
||||
#define NDUID_CHRLEN 40
|
||||
#define NDUID_STRLEN (NDUID_CHRLEN + 1)
|
||||
|
||||
/* static configuration */
|
||||
static ep_t inep;
|
||||
static ep_t outep;
|
||||
static uint interface_num;
|
||||
|
||||
usb_transport::usb_transport()
|
||||
: m_inep(inep),
|
||||
m_outep(outep),
|
||||
m_interface_num(interface_num)
|
||||
{
|
||||
}
|
||||
|
||||
usb_transport::~usb_transport()
|
||||
{
|
||||
delete[] m_rx_buffer;
|
||||
delete[] m_tx_buffer;
|
||||
}
|
||||
|
||||
static void usbll_dump_packet(const uint8_t *buf, size_t len, bool tx)
|
||||
{
|
||||
const struct usbll_header *header = (const struct usbll_header *)buf;
|
||||
char traceheader[128];
|
||||
|
||||
#if LOCAL_TRACE
|
||||
//hexdump8_ex(buf, len, 0);
|
||||
#endif
|
||||
|
||||
snprintf(traceheader, sizeof(traceheader), "%s len %5d txid 0x%08x rxid 0x%08x command 0x%x: ",
|
||||
tx ? "TX" : "RX", (int)len, header->txid, header->rxid, header->command);
|
||||
|
||||
switch (header->command) {
|
||||
case usbll_null:
|
||||
printf("%s null\n", traceheader);
|
||||
break;
|
||||
case usbll_rst:
|
||||
printf("%s rst\n", traceheader);
|
||||
break;
|
||||
case usbll_syn: {
|
||||
const struct usbll_syn_header *syn_header = (const struct usbll_syn_header *)(header + 1);
|
||||
char nduid[NDUID_STRLEN];
|
||||
memcpy(nduid, syn_header->nduid, NDUID_CHRLEN);
|
||||
nduid[NDUID_CHRLEN] = 0;
|
||||
|
||||
if (len >= sizeof(struct usbll_header) + sizeof(struct usbll_syn_header))
|
||||
printf("%s syn, nduid '%s' mtu %u, heartbeat %u, timeout %u\n",
|
||||
traceheader, nduid, syn_header->mtu, syn_header->heartbeat_interval, syn_header->timeout);
|
||||
else
|
||||
printf("%s syn, nduid '%s' mtu %u\n", traceheader, nduid, syn_header->mtu);
|
||||
|
||||
break;
|
||||
}
|
||||
case usbll_data:
|
||||
printf("%s data\n", traceheader);
|
||||
break;
|
||||
default:
|
||||
printf("%s unknown\n", traceheader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status_t usb_transport::usb_cb(usb_callback_op_t op, const union usb_callback_args *args)
|
||||
{
|
||||
LTRACEF("op %u, args %p\n", op, args);
|
||||
|
||||
if (op == USB_CB_ONLINE) {
|
||||
usbc_setup_endpoint(m_inep, USB_IN, 0x40);
|
||||
usbc_setup_endpoint(m_outep, USB_OUT, 0x40);
|
||||
|
||||
m_online = true;
|
||||
} else if (op == USB_CB_OFFLINE) {
|
||||
m_online = false;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t usb_transport::ep_cb_rx(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
#if 0 && LOCAL_TRACE
|
||||
LTRACEF("ep %u transfer %p\n", endpoint, t);
|
||||
usbc_dump_transfer(t);
|
||||
|
||||
if (t->result >= 0) {
|
||||
hexdump8(t->buf, t->bufpos);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_rx_transfer_queued = false;
|
||||
|
||||
the_app->signal_irq();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t usb_transport::ep_cb_tx(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
m_tx_transfer_queued = false;
|
||||
|
||||
the_app->signal_irq();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static void get_nduid(uint8_t *buf)
|
||||
{
|
||||
for (int i = 0; i < NDUID_CHRLEN; i++) {
|
||||
buf[i] = '0' + i;
|
||||
}
|
||||
}
|
||||
|
||||
bool usb_transport::prepare_tx_packet()
|
||||
{
|
||||
DEBUG_ASSERT(m_tx_transfer_queued == false);
|
||||
|
||||
struct usbll_header *header = (struct usbll_header *)m_tx_buffer;
|
||||
header->magic = USBLL_MAGIC;
|
||||
header->version = USBLL_VERSION;
|
||||
header->txid = m_txid;
|
||||
header->rxid = m_rxid;
|
||||
|
||||
m_tx_transfer.buflen = 0;
|
||||
|
||||
switch (m_state) {
|
||||
case STATE_LISTEN: {
|
||||
LTRACEF("STATE_LISTEN, constructing syn packet\n");
|
||||
// we need to send a syn packet
|
||||
header->command = usbll_syn;
|
||||
|
||||
struct usbll_syn_header *syn = (struct usbll_syn_header *)(header + 1);
|
||||
get_nduid(syn->nduid);
|
||||
syn->mtu = 4096;
|
||||
syn->heartbeat_interval = 250;
|
||||
syn->timeout = 1000;
|
||||
syn->data_offset = sizeof(struct usbll_syn_header);
|
||||
syn->data_length = 0;
|
||||
|
||||
m_tx_transfer.buflen = sizeof(*header) + sizeof(*syn);
|
||||
|
||||
m_state = STATE_SYNSENT;
|
||||
return true;
|
||||
}
|
||||
case STATE_SYNSENT:
|
||||
if (current_time() - m_last_tx_time > 1000) {
|
||||
// retransmit SYN
|
||||
m_state = STATE_LISTEN;
|
||||
}
|
||||
break;
|
||||
case STATE_ESTABLISHED: {
|
||||
if (current_time() - m_last_tx_time > 250) { // XXX use negotiated numbers
|
||||
header->command = usbll_null;
|
||||
m_tx_transfer.buflen = sizeof(*header);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ask the mux layer for any data
|
||||
ssize_t len = m_mux->prepare_tx_packet((uint8_t *)(header + 1), USB_TRANSFER_LEN - sizeof(struct usbll_header));
|
||||
if (len > 0) {
|
||||
header->command = usbll_data;
|
||||
m_tx_transfer.buflen = sizeof(struct usbll_header) + len;
|
||||
// make sure we're not an even multiple of a usb packet size
|
||||
if ((m_tx_transfer.buflen % 64) == 0)
|
||||
m_tx_transfer.buflen++;
|
||||
DEBUG_ASSERT(m_tx_transfer.buflen <= USB_TRANSFER_LEN);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//LTRACEF("other state, doing nothing (for now)\n");
|
||||
;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool usb_transport::handle_rx_packet(const uint8_t *buf, size_t len)
|
||||
{
|
||||
DEBUG_ASSERT(buf);
|
||||
DEBUG_ASSERT(len <= USB_TRANSFER_LEN);
|
||||
|
||||
LTRACEF("buf %p, len %zu\n", buf, len);
|
||||
|
||||
const struct usbll_header *header = (const struct usbll_header *)buf;
|
||||
|
||||
if (len < sizeof(struct usbll_header))
|
||||
return false;
|
||||
if (header->magic != USBLL_MAGIC)
|
||||
return false;
|
||||
if (header->version != USBLL_VERSION)
|
||||
return false;
|
||||
|
||||
LTRACEF("state %u, command %u\n", m_state, header->command);
|
||||
#if TRACE_PACKETS
|
||||
usbll_dump_packet(buf, len, false);
|
||||
#endif
|
||||
|
||||
switch (m_state) {
|
||||
case STATE_LISTEN:
|
||||
case STATE_SYNSENT:
|
||||
// they're synning us back
|
||||
if (header->command == usbll_syn) {
|
||||
m_rxid = header->txid;
|
||||
if (m_state == STATE_SYNSENT) {
|
||||
LTRACEF("moving to ESTABLISHED state\n");
|
||||
m_state = STATE_ESTABLISHED;
|
||||
m_mux->set_online(true);
|
||||
}
|
||||
} else {
|
||||
LTRACEF("non SYN packet in LISTEN/SYNSENT state\n");
|
||||
}
|
||||
break;
|
||||
case STATE_ESTABLISHED:
|
||||
if (header->command == usbll_data) {
|
||||
// pass it up to the mux
|
||||
m_mux->process_rx_packet((const uint8_t * )(header + 1), len - sizeof(struct usbll_header));
|
||||
} else if (header->command == usbll_null) {
|
||||
// we don't care
|
||||
} else {
|
||||
LTRACEF("non DATA/NULL packet in ESTABLISHED state\n");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
lk_time_t usb_transport::do_work()
|
||||
{
|
||||
LTRACE_ENTRY;
|
||||
|
||||
// if we're offline, nothing to do
|
||||
if (m_online == false) {
|
||||
// nothing to do
|
||||
return 1000; // tell the main app to try again in 1000ms
|
||||
}
|
||||
|
||||
// see if we're not receiving for some reason
|
||||
if (!m_rx_transfer_queued) {
|
||||
// potentially process data here
|
||||
if (m_rx_transfer.bufpos > 0)
|
||||
handle_rx_packet((const uint8_t *)m_rx_transfer.buf, m_rx_transfer.bufpos);
|
||||
|
||||
m_rx_transfer.callback = &ep_cb_rx_static;
|
||||
m_rx_transfer.result = 0;
|
||||
m_rx_transfer.buf = m_rx_buffer;
|
||||
m_rx_transfer.buflen = USB_TRANSFER_LEN;
|
||||
m_rx_transfer.bufpos = 0;
|
||||
m_rx_transfer.extra = this;
|
||||
m_rx_transfer_queued = true;
|
||||
|
||||
usbc_queue_rx(m_outep, &m_rx_transfer);
|
||||
}
|
||||
|
||||
// check to see if we have some pending tx data
|
||||
if (!m_tx_transfer_queued) {
|
||||
if (prepare_tx_packet()) {
|
||||
// queue it
|
||||
m_tx_transfer.callback = &ep_cb_tx_static;
|
||||
m_tx_transfer.result = 0;
|
||||
m_tx_transfer.buf = m_tx_buffer;
|
||||
m_tx_transfer.bufpos = 0;
|
||||
m_tx_transfer.extra = this;
|
||||
m_tx_transfer_queued = true;
|
||||
m_last_tx_time = current_time();
|
||||
|
||||
#if TRACE_PACKETS
|
||||
usbll_dump_packet(m_tx_buffer, m_tx_transfer.buflen, true);
|
||||
#endif
|
||||
|
||||
usbc_queue_tx(m_inep, &m_tx_transfer);
|
||||
}
|
||||
}
|
||||
|
||||
return INFINITE_TIME;
|
||||
}
|
||||
|
||||
status_t usb_transport::init()
|
||||
{
|
||||
#define W(w) (w & 0xff), (w >> 8)
|
||||
#define W3(w) (w & 0xff), ((w >> 8) & 0xff), ((w >> 16) & 0xff)
|
||||
|
||||
// build a descriptor for it
|
||||
uint8_t if_descriptor[] = {
|
||||
0x09, /* length */
|
||||
INTERFACE, /* type */
|
||||
(uint8_t)m_interface_num,/* interface num */
|
||||
0x00, /* alternates */
|
||||
0x02, /* endpoint count */
|
||||
0xff, /* interface class */
|
||||
0x47, /* interface subclass */
|
||||
0x11, /* interface protocol */
|
||||
0x00, /* string index */
|
||||
|
||||
/* endpoint IN */
|
||||
0x07, /* length */
|
||||
ENDPOINT, /* type */
|
||||
(uint8_t)(m_inep | 0x80), /* address: 1 IN */
|
||||
0x02, /* type: bulk */
|
||||
W(64), /* max packet size: 64 */
|
||||
00, /* interval */
|
||||
|
||||
/* endpoint OUT */
|
||||
0x07, /* length */
|
||||
ENDPOINT, /* type */
|
||||
(uint8_t)m_outep, /* address: 1 OUT */
|
||||
0x02, /* type: bulk */
|
||||
W(64), /* max packet size: 64 */
|
||||
00, /* interval */
|
||||
};
|
||||
|
||||
LTRACEF("epin %u, epout %u\n", m_inep, m_outep);
|
||||
|
||||
usb_append_interface_lowspeed(if_descriptor, sizeof(if_descriptor));
|
||||
usb_append_interface_highspeed(if_descriptor, sizeof(if_descriptor));
|
||||
|
||||
usb_register_callback(usb_cb_static, this);
|
||||
|
||||
// clear the state
|
||||
m_state = STATE_LISTEN;
|
||||
m_online = false;
|
||||
|
||||
// allocate some buffers
|
||||
m_rx_buffer = new uint8_t[USB_TRANSFER_LEN];
|
||||
m_rx_transfer = { };
|
||||
m_rx_transfer_queued = false;
|
||||
m_tx_buffer = new uint8_t[USB_TRANSFER_LEN];
|
||||
m_tx_transfer = { };
|
||||
m_tx_transfer_queued = false;
|
||||
|
||||
m_rxid = 0;
|
||||
m_txid = rand();
|
||||
m_last_tx_time = 0;
|
||||
|
||||
return NO_ERROR;
|
||||
|
||||
#undef W
|
||||
#undef W3
|
||||
}
|
||||
|
||||
} // namespace mocom
|
||||
|
||||
// C api to configure the endpoints
|
||||
status_t mocom_configure_usb_endpoints(uint _interface, ep_t _inep, ep_t _outep)
|
||||
{
|
||||
LTRACEF("interface %u, inep %u, outep %u\n", _interface, _inep, _outep);
|
||||
|
||||
mocom::inep = _inep;
|
||||
mocom::outep = _outep;
|
||||
mocom::interface_num = _interface;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
116
app/mocom/usb.hpp
Normal file
116
app/mocom/usb.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <dev/usbc.h>
|
||||
#include <dev/usb.h>
|
||||
#include <kernel/spinlock.h>
|
||||
#include "transport.hpp"
|
||||
#include <lib/cpputils/nocopy.hpp>
|
||||
|
||||
namespace mocom {
|
||||
|
||||
class usb_transport : public transport {
|
||||
public:
|
||||
usb_transport();
|
||||
virtual ~usb_transport();
|
||||
|
||||
virtual status_t init() override;
|
||||
virtual lk_time_t do_work() override;
|
||||
|
||||
private:
|
||||
// in/out endpoints
|
||||
ep_t m_inep;
|
||||
ep_t m_outep;
|
||||
uint m_interface_num;
|
||||
|
||||
enum {
|
||||
STATE_LISTEN,
|
||||
STATE_SYNSENT,
|
||||
STATE_ESTABLISHED,
|
||||
} m_state;
|
||||
volatile bool m_online;
|
||||
|
||||
// transfer lock
|
||||
spin_lock_t lock;
|
||||
|
||||
static const size_t USB_TRANSFER_LEN = 4096;
|
||||
|
||||
// rx transfers
|
||||
bool m_rx_transfer_queued;
|
||||
usbc_transfer_t m_rx_transfer;
|
||||
uint8_t *m_rx_buffer = nullptr;
|
||||
|
||||
// tx transfers
|
||||
bool m_tx_transfer_queued;
|
||||
usbc_transfer_t m_tx_transfer;
|
||||
uint8_t *m_tx_buffer = nullptr;
|
||||
|
||||
uint32_t m_txid;
|
||||
uint32_t m_rxid;
|
||||
lk_time_t m_last_tx_time;
|
||||
|
||||
// usb layer callbacks
|
||||
status_t usb_cb(usb_callback_op_t op, const union usb_callback_args *args);
|
||||
status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
|
||||
status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
|
||||
|
||||
static status_t usb_cb_static(void *cookie, usb_callback_op_t op, const union usb_callback_args *args);
|
||||
static status_t ep_cb_rx_static(ep_t endpoint, usbc_transfer_t *t);
|
||||
static status_t ep_cb_tx_static(ep_t endpoint, usbc_transfer_t *t);
|
||||
|
||||
// internal routines
|
||||
bool prepare_tx_packet();
|
||||
bool handle_rx_packet(const uint8_t *buf, size_t len);
|
||||
|
||||
// no copy
|
||||
usb_transport(const usb_transport &);
|
||||
usb_transport& operator=(const usb_transport &);
|
||||
};
|
||||
|
||||
inline status_t usb_transport::usb_cb_static(void *cookie, usb_callback_op_t op, const union usb_callback_args *args) {
|
||||
usb_transport *t = static_cast<usb_transport *>(cookie);
|
||||
|
||||
return t->usb_cb(op, args);
|
||||
}
|
||||
|
||||
inline status_t usb_transport::ep_cb_rx_static(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
usb_transport *_t = static_cast<usb_transport *>(t->extra);
|
||||
return _t->ep_cb_rx(endpoint, t);
|
||||
}
|
||||
|
||||
inline status_t usb_transport::ep_cb_tx_static(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
usb_transport *_t = static_cast<usb_transport *>(t->extra);
|
||||
return _t->ep_cb_tx(endpoint, t);
|
||||
}
|
||||
|
||||
inline transport *create_usb_transport()
|
||||
{
|
||||
usb_transport *u = new usb_transport();
|
||||
return u;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
80
lib/cpputils/include/lib/cpputils/autolocker.hpp
Normal file
80
lib/cpputils/include/lib/cpputils/autolocker.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <kernel/mutex.h>
|
||||
#include <kernel/spinlock.h>
|
||||
#include "nocopy.hpp"
|
||||
|
||||
// XXX quick lock wrappers. need to move somewhere else
|
||||
|
||||
namespace lk {
|
||||
|
||||
class automutex : nocopy {
|
||||
public:
|
||||
automutex(mutex_t *mutex) : m_lock(mutex) {
|
||||
mutex_acquire(m_lock);
|
||||
}
|
||||
|
||||
~automutex() {
|
||||
release();
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (m_lock) {
|
||||
mutex_release(m_lock);
|
||||
m_lock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutex_t *m_lock;
|
||||
};
|
||||
|
||||
// XXX this doesn't seem to be terribly efficient on the release case
|
||||
class autospinlock : nocopy {
|
||||
public:
|
||||
autospinlock(spin_lock_t *lock, spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
|
||||
: m_lock(lock), m_flags(flags) {
|
||||
spin_lock_save(m_lock, &m_state, m_flags);
|
||||
}
|
||||
|
||||
~autospinlock() {
|
||||
release();
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (m_lock) {
|
||||
spin_unlock_restore(m_lock, m_state, m_flags);
|
||||
m_lock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
spin_lock_t *m_lock;
|
||||
spin_lock_save_flags_t m_flags;
|
||||
spin_lock_saved_state_t m_state;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
35
lib/cpputils/include/lib/cpputils/nocopy.hpp
Normal file
35
lib/cpputils/include/lib/cpputils/nocopy.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace lk {
|
||||
|
||||
struct nocopy {
|
||||
// no copy
|
||||
nocopy() = default;
|
||||
nocopy(const nocopy &) = delete;
|
||||
nocopy& operator=(const nocopy &) = delete;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
0
lib/cpputils/null.cpp
Normal file
0
lib/cpputils/null.cpp
Normal file
15
lib/cpputils/rules.mk
Normal file
15
lib/cpputils/rules.mk
Normal file
@@ -0,0 +1,15 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
MODULE_DEPS := \
|
||||
|
||||
MODULE_SRCS := \
|
||||
$(LOCAL_DIR)/null.cpp
|
||||
|
||||
ifeq ($(WITH_CPP_SUPPORT),true)
|
||||
MODULE_SRCS += \
|
||||
|
||||
endif
|
||||
|
||||
include make/module.mk
|
||||
@@ -5,3 +5,4 @@ include project/virtual/minip.mk
|
||||
# Console serial port is on pins PA9(TX) and PB7(RX)
|
||||
|
||||
include project/virtual/fs.mk
|
||||
include project/virtual/mocom.mk
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
include project/target/stm32f746g-disco.mk
|
||||
include project/virtual/test.mk
|
||||
include project/virtual/minip.mk
|
||||
include project/virtual/mocom.mk
|
||||
include project/virtual/fs.mk
|
||||
|
||||
MODULES += \
|
||||
lib/fs \
|
||||
app/loader
|
||||
|
||||
include project/virtual/fs.mk
|
||||
|
||||
LK_HEAP_IMPLEMENTATION=cmpctmalloc
|
||||
|
||||
# Console serial port is on pins PA9(TX) and PB7(RX)
|
||||
|
||||
5
project/virtual/mocom.mk
Normal file
5
project/virtual/mocom.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
# modules related to mocom
|
||||
|
||||
MODULES += \
|
||||
app/mocom
|
||||
|
||||
@@ -27,6 +27,7 @@ GLOBAL_DEFINES += \
|
||||
|
||||
MODULE_DEPS += \
|
||||
app/accelerometer \
|
||||
dev/usb/class/bulktest \
|
||||
|
||||
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
|
||||
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include <compiler.h>
|
||||
#include <dev/usb.h>
|
||||
#include <dev/usbc.h>
|
||||
#include <dev/usb/class/bulktest.h>
|
||||
#include <hw/usb.h>
|
||||
#include <lk/init.h>
|
||||
#include <app/mocom/usb.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
@@ -80,34 +82,6 @@ static const uint8_t cfg_descr[] = {
|
||||
|
||||
static const uchar langid[] = { 0x04, 0x03, 0x09, 0x04 };
|
||||
|
||||
static const uint8_t if_descriptor_lowspeed[] = {
|
||||
0x09, /* length */
|
||||
INTERFACE, /* type */
|
||||
0x01, /* interface num */
|
||||
0x00, /* alternates */
|
||||
0x02, /* endpoint count */
|
||||
0xff, /* interface class */
|
||||
0xff, /* interface subclass */
|
||||
0x00, /* interface protocol */
|
||||
0x00, /* string index */
|
||||
|
||||
/* endpoint 1 IN */
|
||||
0x07, /* length */
|
||||
ENDPOINT, /* type */
|
||||
0x81, /* address: 1 IN */
|
||||
0x02, /* type: bulk */
|
||||
W(64), /* max packet size: 64 */
|
||||
00, /* interval */
|
||||
|
||||
/* endpoint 1 OUT */
|
||||
0x07, /* length */
|
||||
ENDPOINT, /* type */
|
||||
0x01, /* address: 1 OUT */
|
||||
0x02, /* type: bulk */
|
||||
W(64), /* max packet size: 64 */
|
||||
00, /* interval */
|
||||
};
|
||||
|
||||
usb_config config = {
|
||||
.lowspeed = {
|
||||
.device = USB_DESC_STATIC(dev_descr),
|
||||
@@ -123,97 +97,19 @@ usb_config config = {
|
||||
.langid = USB_DESC_STATIC(langid),
|
||||
};
|
||||
|
||||
static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
|
||||
static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
|
||||
|
||||
static void queue_rx(void)
|
||||
{
|
||||
static usbc_transfer_t transfer;
|
||||
static uint8_t buf[512];
|
||||
|
||||
transfer.callback = &ep_cb_rx;
|
||||
transfer.result = 0;
|
||||
transfer.buf = &buf;
|
||||
transfer.buflen = sizeof(buf);
|
||||
transfer.bufpos = 0;
|
||||
transfer.extra = 0;
|
||||
|
||||
usbc_queue_rx(1, &transfer);
|
||||
}
|
||||
|
||||
static void queue_tx(void)
|
||||
{
|
||||
static usbc_transfer_t transfer;
|
||||
static uint8_t buf[512];
|
||||
|
||||
for (uint i = 0; i < sizeof(buf); i++) {
|
||||
buf[i] = ~i;
|
||||
}
|
||||
|
||||
transfer.callback = &ep_cb_tx;
|
||||
transfer.result = 0;
|
||||
transfer.buf = &buf;
|
||||
transfer.buflen = sizeof(buf);
|
||||
transfer.bufpos = 0;
|
||||
transfer.extra = 0;
|
||||
|
||||
usbc_queue_tx(1, &transfer);
|
||||
}
|
||||
|
||||
static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
#if LOCAL_TRACE
|
||||
LTRACEF("ep %u transfer %p\n", endpoint, t);
|
||||
usbc_dump_transfer(t);
|
||||
|
||||
if (t->result >= 0) {
|
||||
hexdump8(t->buf, t->bufpos);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (t->result >= 0)
|
||||
queue_rx();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t)
|
||||
{
|
||||
#if LOCAL_TRACE
|
||||
LTRACEF("ep %u transfer %p\n", endpoint, t);
|
||||
usbc_dump_transfer(t);
|
||||
#endif
|
||||
|
||||
if (t->result >= 0)
|
||||
queue_tx();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
static status_t usb_cb(void *cookie, usb_callback_op_t op, const union usb_callback_args *args)
|
||||
{
|
||||
LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args);
|
||||
|
||||
if (op == USB_CB_ONLINE) {
|
||||
usbc_setup_endpoint(1, USB_IN, 0x40);
|
||||
usbc_setup_endpoint(1, USB_OUT, 0x40);
|
||||
|
||||
queue_rx();
|
||||
queue_tx();
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void target_usb_setup(void)
|
||||
{
|
||||
usb_setup(&config);
|
||||
printf("appending interfaces\n");
|
||||
usb_append_interface_lowspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
|
||||
usb_append_interface_highspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
|
||||
|
||||
usb_add_string("LK", 1);
|
||||
usb_add_string("LK Industries", 2);
|
||||
|
||||
usb_register_callback(&usb_cb, NULL);
|
||||
/* add our bulk endpoint class device */
|
||||
usb_class_bulktest_init(1, 1, 1);
|
||||
|
||||
/* configure the mocom stuff */
|
||||
mocom_configure_usb_endpoints(2, 2, 2);
|
||||
|
||||
usb_start();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <dev/usb/class/bulktest.h>
|
||||
#include <hw/usb.h>
|
||||
#include <lk/init.h>
|
||||
#include <app/mocom/usb.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
@@ -107,5 +108,8 @@ void target_usb_setup(void)
|
||||
/* add our bulk endpoint class device */
|
||||
usb_class_bulktest_init(1, 1, 1);
|
||||
|
||||
/* configure the mocom stuff */
|
||||
mocom_configure_usb_endpoints(2, 2, 2);
|
||||
|
||||
usb_start();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user