Skip to content

Instantly share code, notes, and snippets.

@kevinmehall
Created May 11, 2012 22:11
Show Gist options
  • Save kevinmehall/2662715 to your computer and use it in GitHub Desktop.
Save kevinmehall/2662715 to your computer and use it in GitHub Desktop.
FIFO ring buffer for USB packets on xmega
// Bufferred BULK streaming
// http://nonolithlabs.com
// (C) 2011 Kevin Mehall (Nonolith Labs) <km@kevinmehall.net>
//
// Licensed under the terms of the GNU GPLv3+
#include "packetbuffer.h"
// CEE to PC buffer
Ringbuf in_ring;
unsigned char in_buf[PACKETS_BUFFER][IN_PACKET_SIZE];
// PC to CEE buffers
Ringbuf out_a_ring;
unsigned char out_a_buf[PACKETS_BUFFER][OUT_PACKET_SIZE];
Ringbuf out_b_ring;
unsigned char out_b_buf[PACKETS_BUFFER][OUT_PACKET_SIZE];
void packetbuf_endpoint_init(void){
USB_ep_in_init(1, USB_EP_TYPE_BULK_gc, IN_PACKET_SIZE);
USB_ep_out_init(2, USB_EP_TYPE_BULK_gc, OUT_PACKET_SIZE);
packetbuf_reset();
}
void packetbuf_reset(void){
ringbuf_reset(&in_ring);
ringbuf_reset(&out_a_ring);
ringbuf_reset(&out_b_ring);
USB_ep_in_reset(1);
USB_ep_out_reset(2);
USB_ep_out_reset(3);
ringbuf_usb_start_out(2, &out_a_ring, (uint8_t*) out_a_buf, OUT_PACKET_SIZE);
ringbuf_usb_start_out(3, &out_b_ring, (uint8_t*) out_b_buf, OUT_PACKET_SIZE);
}
void packetbuf_endpoint_poll(void){
ringbuf_usb_poll_in(1, &in_ring, (uint8_t*) in_buf, IN_PACKET_SIZE);
ringbuf_usb_poll_out(2, &out_a_ring, (uint8_t*) out_a_buf, OUT_PACKET_SIZE);
ringbuf_usb_poll_out(3, &out_b_ring, (uint8_t*) out_b_buf, OUT_PACKET_SIZE);
}
// Bufferred BULK streaming
// http://nonolithlabs.com
// (C) 2012 Kevin Mehall (Nonolith Labs) <km@kevinmehall.net>
// (C) 2011 Ian Daniher (Nonolith Labs) <ian@nonolithlabs.com>
//
// Licensed under the terms of the GNU GPLv3+
#include <usb.h>
#define IN_PACKET_SIZE 64
#define OUT_PACKET_SIZE 16
#define PACKETS_BUFFER 16
typedef struct ringbuf{
// Index of the next readable position of the buffer
uint8_t start;
// Index of the next or pending writable position of the buffer
uint8_t end;
// Number of valid buffer slots
uint8_t count;
} Ringbuf;
/// Reset / initialize a ring buffer structure
inline static void ringbuf_reset(Ringbuf *r){
r->start = r->end = r->count = 0;
}
inline static bool ringbuf_can_read(Ringbuf *r){return r->count>0;}
inline static bool ringbuf_can_write(Ringbuf *r){return r->count < PACKETS_BUFFER-1;}
inline static void ringbuf_after_take(Ringbuf *r){
r->count--;
r->start = (r->start+1)%PACKETS_BUFFER;
}
inline static void ringbuf_after_put(Ringbuf *r){
r->count++;
r->end = (r->end+1)%PACKETS_BUFFER;
}
inline static void ringbuf_usb_poll_in(uint8_t ep, Ringbuf *r, uint8_t* buf, uint8_t size){
if (USB_ep_in_sent(ep) && ringbuf_can_read(r)){
cli();
USB_ep_in_start(ep, &buf[r->start*size], size);
ringbuf_after_take(r);
sei();
}
}
inline static void ringbuf_usb_start_out(uint8_t ep, Ringbuf *r, uint8_t* buf, uint8_t size){
USB_ep_out_start(ep, &buf[r->end*size]);
ringbuf_after_put(r);
}
inline static void ringbuf_usb_poll_out(uint8_t ep, Ringbuf *r, uint8_t* buf, uint8_t size){
if (USB_ep_out_received(ep) && ringbuf_can_write(r)){
cli();
ringbuf_usb_start_out(ep, r, buf, size);
sei();
}
}
// CEE to PC buffer
extern Ringbuf in_ring;
extern unsigned char in_buf[PACKETS_BUFFER][IN_PACKET_SIZE];
// PC to CEE buffers
extern Ringbuf out_a_ring;
extern unsigned char out_a_buf[PACKETS_BUFFER][OUT_PACKET_SIZE];
extern Ringbuf out_b_ring;
extern unsigned char out_b_buf[PACKETS_BUFFER][OUT_PACKET_SIZE];
//determine if there is space in the slave-to-host ring buffer for another packet
inline static bool inbuf_can_write(void){return ringbuf_can_write(&in_ring);}
//determine if there are packets received from the host
inline static bool outbuf_a_can_read(void){return ringbuf_can_read(&out_a_ring);}
inline static bool outbuf_b_can_read(void){return ringbuf_can_read(&out_b_ring);}
inline static void outbuf_a_done_read(void){ringbuf_after_take(&out_a_ring);}
inline static void outbuf_b_done_read(void){ringbuf_after_take(&out_b_ring);}
inline static void inbuf_done_write(void){ringbuf_after_put(&in_ring);}
//returns location of buffer to fill
inline static uint8_t* inbuf_write_position(void){return in_buf[in_ring.end];}
inline static uint8_t* outbuf_a_read_position(void){return out_a_buf[out_a_ring.start];}
inline static uint8_t* outbuf_b_read_position(void){return out_b_buf[out_b_ring.start];}
void packetbuf_endpoint_init(void);
void packetbuf_reset(void);
void packetbuf_endpoint_poll(void);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment