trunk
parent
31480f2f22
commit
6814cb57dd
@ -0,0 +1,21 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef MATH_MISC_HPP
|
||||
#define MATH_MISC_HPP
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Return num/den rounded to the nearest integer. Undefined for negatives
|
||||
// (TODO clean it up in the future)
|
||||
template<typename T>
|
||||
static inline T rounded_div(T num, T den)
|
||||
{
|
||||
T quo = num/den, rem = num%den;
|
||||
if (rem >= den/2)
|
||||
quo++;
|
||||
return quo;
|
||||
}
|
||||
|
||||
#endif // !defined(MATH_MISC_HPP)
|
@ -0,0 +1,46 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef SPI_HPP
|
||||
#define SPI_HPP
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Generic SPI interface class. Generally assumes a non interrupt driven style
|
||||
// interface.
|
||||
class spi
|
||||
{
|
||||
public:
|
||||
virtual ~spi() = default;
|
||||
|
||||
// Transfer one byte, returning the data received.
|
||||
virtual uint8_t transfer(uint8_t data) = 0;
|
||||
|
||||
// Transfer a packet. Does not manipulate chip selects.
|
||||
//
|
||||
// data_out: data to send
|
||||
// data_in: buffer to receive response. May equal data_out; may be null
|
||||
// length: number of bytes to send
|
||||
//
|
||||
// Implementer: override only if you have a faster approach.
|
||||
virtual void transfer_block(
|
||||
uint8_t const * data_out,
|
||||
uint8_t * data_in,
|
||||
size_t length
|
||||
)
|
||||
{
|
||||
if (data_in)
|
||||
{
|
||||
for (size_t i = 0; i < length; i++)
|
||||
data_in[i] = transfer(data_out[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < length; i++)
|
||||
transfer(data_out[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !defined(SPI_HPP)
|
@ -0,0 +1,154 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef SPI_AVRDX_HPP
|
||||
#define SPI_AVRDX_HPP
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <avrstuff/spi.hpp>
|
||||
#include <avr/io.h>
|
||||
|
||||
template<int NSpi>
|
||||
class spi_avrdx: public spi
|
||||
{
|
||||
public:
|
||||
enum class clockdiv: uint8_t
|
||||
{
|
||||
div2 = SPI_PRESC_DIV4_gc | SPI_CLK2X_bm,
|
||||
div4 = SPI_PRESC_DIV4_gc,
|
||||
div8 = SPI_PRESC_DIV16_gc | SPI_CLK2X_bm,
|
||||
div16 = SPI_PRESC_DIV16_gc,
|
||||
div32 = SPI_PRESC_DIV64_gc | SPI_CLK2X_bm,
|
||||
div64 = SPI_PRESC_DIV64_gc,
|
||||
div128 = SPI_PRESC_DIV128_gc,
|
||||
};
|
||||
|
||||
virtual ~spi_avrdx() = default;
|
||||
|
||||
virtual uint8_t transfer(uint8_t data) override
|
||||
{
|
||||
transfer_block_u8(&data, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
void transfer_block_u8(
|
||||
uint8_t const * data_out,
|
||||
uint8_t * data_in,
|
||||
uint8_t length
|
||||
)
|
||||
{
|
||||
Spi()->INTFLAGS = 0xFF;
|
||||
|
||||
if (!data_in)
|
||||
{
|
||||
// This loop can maintain a 93% transmit duty cycle
|
||||
// at div/2
|
||||
for (uint8_t i = 0; i < length; i++)
|
||||
{
|
||||
while (!(Spi()->INTFLAGS & SPI_DREIF_bm));
|
||||
Spi()->DATA = data_out[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This loop can maintain a 58% transmit duty cycle
|
||||
// at div/2. It's not a fully saturated link, but it's
|
||||
// better than 50% (so higher throughput than running
|
||||
// one divider lower). If there is any further
|
||||
// optimization to be had, it's in the middle loop.
|
||||
|
||||
uint8_t i_out = 0, i_in = 0, discard = 2;
|
||||
while (i_out < length && discard)
|
||||
{
|
||||
uint8_t flags = Spi()->INTFLAGS;
|
||||
|
||||
if (flags & (SPI_RXCIF_bm | SPI_BUFOVF_bm | SPI_TXCIF_bm))
|
||||
{
|
||||
(void) Spi()->DATA;
|
||||
discard--;
|
||||
}
|
||||
|
||||
if (flags & SPI_DREIF_bm)
|
||||
Spi()->DATA = data_out[i_out++];
|
||||
}
|
||||
|
||||
while (i_out < length)
|
||||
{
|
||||
uint8_t flags = Spi()->INTFLAGS;
|
||||
|
||||
if (flags & (SPI_RXCIF_bm | SPI_BUFOVF_bm | SPI_TXCIF_bm))
|
||||
{
|
||||
uint8_t data = Spi()->DATA;
|
||||
data_in[i_in++] = data;
|
||||
}
|
||||
|
||||
if (flags & SPI_DREIF_bm)
|
||||
Spi()->DATA = data_out[i_out++];
|
||||
}
|
||||
|
||||
while (i_in < length)
|
||||
{
|
||||
uint8_t flags = Spi()->INTFLAGS;
|
||||
|
||||
if (flags & (SPI_RXCIF_bm | SPI_BUFOVF_bm | SPI_TXCIF_bm))
|
||||
{
|
||||
uint8_t data = Spi()->DATA;
|
||||
if (discard)
|
||||
discard--;
|
||||
else
|
||||
data_in[i_in++] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void transfer_block(
|
||||
uint8_t const * data_out,
|
||||
uint8_t * data_in,
|
||||
size_t length
|
||||
) override
|
||||
{
|
||||
while (length > 255)
|
||||
{
|
||||
transfer_block_u8(data_out, data_in, 255);
|
||||
data_out += 255;
|
||||
length -= 255;
|
||||
if (data_in)
|
||||
data_in += 255;
|
||||
}
|
||||
if (length)
|
||||
transfer_block_u8(data_out, data_in, length);
|
||||
}
|
||||
|
||||
void init(clockdiv fsck, bool msb_first, uint8_t mode)
|
||||
{
|
||||
Spi()->CTRLB = SPI_BUFEN_bm | SPI_BUFWR_bm | SPI_SSD_bm
|
||||
| (mode & 0x3);
|
||||
|
||||
Spi()->INTCTRL = 0;
|
||||
|
||||
Spi()->CTRLA = 0
|
||||
| (msb_first ? 0 : SPI_DORD_bm)
|
||||
| SPI_MASTER_bm
|
||||
| (uint8_t) fsck
|
||||
| SPI_ENABLE_bm
|
||||
;
|
||||
|
||||
// Pump the FIFO so the discards in the transfer loop match up
|
||||
transfer_block_u8((uint8_t const *) "\0", NULL, 3);
|
||||
}
|
||||
|
||||
SPI_t * Spi() const {
|
||||
return
|
||||
#ifdef SPI0
|
||||
NSpi == 0 ? &SPI0 :
|
||||
#endif
|
||||
#ifdef SPI1
|
||||
NSpi == 1 ? &SPI1 :
|
||||
#endif
|
||||
NULL;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // !defined(SPI_AVRDX_HPP)
|
@ -0,0 +1,80 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#include "midix.hpp"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void midix::rxc()
|
||||
{
|
||||
int c = m_serport.recv();
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
m_message.command = MIDI_ICMD_NOP;
|
||||
m_message_pos = 0;
|
||||
if (m_receiving_sysex)
|
||||
{
|
||||
m_receiving_sysex = false;
|
||||
m_sysex_buf_avail = true;
|
||||
}
|
||||
}
|
||||
else if (m_receiving_sysex)
|
||||
{
|
||||
if (c == MIDI_CMD_END_SYSEX)
|
||||
{
|
||||
if (m_message_pos < MIDIX_SYSEX_LEN)
|
||||
m_sysex_buf[m_message_pos] = 0;
|
||||
else
|
||||
m_sysex_buf[MIDIX_SYSEX_LEN - 1] = 0;
|
||||
|
||||
send();
|
||||
}
|
||||
else if (m_message_pos < MIDIX_SYSEX_LEN)
|
||||
m_sysex_buf[m_message_pos++] = c;
|
||||
}
|
||||
else if (c == MIDI_CMD_START_SYSEX)
|
||||
{
|
||||
if (m_sysex_buf_avail)
|
||||
{
|
||||
m_message.command = MIDI_ICMD_SYSEX;
|
||||
m_message.content = m_sysex_buf;
|
||||
m_message_pos = 0;
|
||||
m_receiving_sysex = true;
|
||||
m_sysex_buf_avail = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_message.command = MIDI_ICMD_SYSEX_OVERFLOW;
|
||||
send();
|
||||
}
|
||||
}
|
||||
else if (c >= 0x80)
|
||||
{
|
||||
m_message.command = (uint8_t) c;
|
||||
m_message_pos = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_message_pos <= sizeof(m_message.arguments))
|
||||
{
|
||||
m_message.arguments[m_message_pos - 1] = c;
|
||||
m_message_pos++;
|
||||
}
|
||||
|
||||
if (m_message.command &&
|
||||
m_message_pos == midi_num_args(m_message.command) + 1)
|
||||
{
|
||||
send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void midix::sysex_release_buffer(uint8_t * buf)
|
||||
{
|
||||
assert(!m_sysex_buf_avail);
|
||||
assert(buf == &m_sysex_buf[0]);
|
||||
buf[0] = 0;
|
||||
m_sysex_buf_avail = true;
|
||||
}
|
Loading…
Reference in new issue