Add simple HPGL parser, PWM output
This commit is contained in:
parent
7234eb8360
commit
57f486a4d2
11 changed files with 439 additions and 8 deletions
|
|
@ -1 +1 @@
|
||||||
223
|
246
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
#define CONFIG_USB_RINGBUFFER_SIZE \
|
#define CONFIG_USB_RINGBUFFER_SIZE \
|
||||||
256
|
256
|
||||||
|
#define CONFIG_BUFFER_MOVEMENTS 32
|
||||||
|
|
|
||||||
196
stm32f103c8t6/src/hgpl.c
Normal file
196
stm32f103c8t6/src/hgpl.c
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
#include "hpgl.h"
|
||||||
|
#include "usb_cdc.h"
|
||||||
|
#include "pwm_output.h"
|
||||||
|
|
||||||
|
unsigned int HPGL_ParseErrorCounter = 0;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
// Last command finished, waiting for more
|
||||||
|
HPGL_Parser_Idle,
|
||||||
|
|
||||||
|
// First byte of instruction has been received, waiting for second one
|
||||||
|
HPGL_Parser_ReceivingInstruction,
|
||||||
|
|
||||||
|
// Receiving the pen number (currently ignored)
|
||||||
|
HPGL_Parser_ReceivingPenNumber,
|
||||||
|
|
||||||
|
// Receiving coordinates after movement/drawing command
|
||||||
|
HPGL_Parser_ReceivingX,
|
||||||
|
HPGL_Parser_ReceivingY,
|
||||||
|
|
||||||
|
HPGL_Parser_Error,
|
||||||
|
} HPGL_ParserState_t;
|
||||||
|
|
||||||
|
// Adds a movement to the queue. Returns false when the queue is currently full
|
||||||
|
static bool HPGL_EnqueueMovement(HPGL_Movement_t movement)
|
||||||
|
{
|
||||||
|
return Output_EnqueueMovement(movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper macro to combine two characters into one integer
|
||||||
|
#define INST(a,b) (((unsigned int)a) << 8 | (unsigned int)b)
|
||||||
|
|
||||||
|
void HPGL_Poll(void)
|
||||||
|
{
|
||||||
|
static HPGL_ParserState_t state = HPGL_Parser_Idle;
|
||||||
|
static char last_character = 0;
|
||||||
|
// Movement which is currently built from received characters
|
||||||
|
static HPGL_Movement_t current_movement;
|
||||||
|
// Movemenet which is waiting to be enqueued if the queue is full
|
||||||
|
static HPGL_Movement_t waiting_movement;
|
||||||
|
|
||||||
|
static bool waiting_for_movement_queue = false;
|
||||||
|
|
||||||
|
if(waiting_for_movement_queue)
|
||||||
|
{
|
||||||
|
if(!HPGL_EnqueueMovement(waiting_movement))
|
||||||
|
{
|
||||||
|
// Still not enough space
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
waiting_for_movement_queue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int received = USBCDC_ReceiveByte();
|
||||||
|
if(received == -1)
|
||||||
|
{
|
||||||
|
// Nothing received
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char character = received;
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case HPGL_Parser_Idle:
|
||||||
|
if(character == '\r' || character == '\n'
|
||||||
|
|| character == ';' || character == ' ')
|
||||||
|
{
|
||||||
|
// Ignore delimiters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(character >= 'A' && character <= 'Z')
|
||||||
|
{
|
||||||
|
// First character of all supported instructions
|
||||||
|
state = HPGL_Parser_ReceivingInstruction;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unsupported command
|
||||||
|
HPGL_ParseErrorCounter++;
|
||||||
|
state = HPGL_Parser_Error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HPGL_Parser_ReceivingInstruction:
|
||||||
|
switch(INST(last_character, character))
|
||||||
|
{
|
||||||
|
case INST('I', 'N'):
|
||||||
|
// Initialise
|
||||||
|
HPGL_ParseErrorCounter = 0;
|
||||||
|
// No parameters expected for this one
|
||||||
|
state = HPGL_Parser_Idle;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INST('S', 'P'):
|
||||||
|
// Set pen
|
||||||
|
state = HPGL_Parser_ReceivingPenNumber;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INST('P', 'U'):
|
||||||
|
// Movement with pen up
|
||||||
|
current_movement.pen_down = false;
|
||||||
|
current_movement.x = 0;
|
||||||
|
current_movement.y = 0;
|
||||||
|
state = HPGL_Parser_ReceivingX;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INST('P', 'D'):
|
||||||
|
// Movement with pen down
|
||||||
|
current_movement.pen_down = true;
|
||||||
|
current_movement.x = 0;
|
||||||
|
current_movement.y = 0;
|
||||||
|
state = HPGL_Parser_ReceivingX;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unsupported instruction
|
||||||
|
state = HPGL_Parser_Error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HPGL_Parser_ReceivingX:
|
||||||
|
case HPGL_Parser_ReceivingY:
|
||||||
|
if(character == ';' || character == '\n')
|
||||||
|
{
|
||||||
|
// Command finished
|
||||||
|
if(!HPGL_EnqueueMovement(current_movement))
|
||||||
|
{
|
||||||
|
// Not enough space in queue
|
||||||
|
waiting_movement = current_movement;
|
||||||
|
waiting_for_movement_queue = true;
|
||||||
|
}
|
||||||
|
state = HPGL_Parser_Idle;
|
||||||
|
}
|
||||||
|
else if(character == ',')
|
||||||
|
{
|
||||||
|
// Next coordinate
|
||||||
|
if(state == HPGL_Parser_ReceivingX)
|
||||||
|
{
|
||||||
|
state = HPGL_Parser_ReceivingY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Next movement
|
||||||
|
if(!HPGL_EnqueueMovement(current_movement))
|
||||||
|
{
|
||||||
|
// Not enough space in queue
|
||||||
|
waiting_movement = current_movement;
|
||||||
|
waiting_for_movement_queue = true;
|
||||||
|
}
|
||||||
|
// Reset coordinates, pen position stays unmodified
|
||||||
|
current_movement.x = 0;
|
||||||
|
current_movement.y = 0;
|
||||||
|
// Receive an X coordinate again
|
||||||
|
state = HPGL_Parser_ReceivingX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(character >= '0' && character <= '9')
|
||||||
|
{
|
||||||
|
unsigned int digit = character - '0';
|
||||||
|
if(state == HPGL_Parser_ReceivingX)
|
||||||
|
{
|
||||||
|
current_movement.x = current_movement.x * 10 + digit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_movement.y = current_movement.y * 10 + digit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No decimal support so far. Sorry.
|
||||||
|
state = HPGL_Parser_Error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HPGL_Parser_ReceivingPenNumber:
|
||||||
|
// Ignore everything except for end of command
|
||||||
|
if(character == ';' || character == '\n')
|
||||||
|
{
|
||||||
|
state = HPGL_Parser_Idle;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HPGL_Parser_Error:
|
||||||
|
// Exit error state only after end of command
|
||||||
|
if(character == '\n' || character == ';')
|
||||||
|
{
|
||||||
|
state = HPGL_Parser_Idle;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_character = character;
|
||||||
|
}
|
||||||
12
stm32f103c8t6/src/hpgl.h
Normal file
12
stm32f103c8t6/src/hpgl.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool pen_down;
|
||||||
|
unsigned int x;
|
||||||
|
unsigned int y;
|
||||||
|
} HPGL_Movement_t;
|
||||||
|
|
||||||
|
void HPGL_Poll(void);
|
||||||
|
|
@ -34,17 +34,19 @@ int main(void)
|
||||||
Clock_Init();
|
Clock_Init();
|
||||||
LED_Init();
|
LED_Init();
|
||||||
USB_Init();
|
USB_Init();
|
||||||
|
Output_Init();
|
||||||
|
|
||||||
LED_ON();
|
LED_ON();
|
||||||
|
|
||||||
uint8_t buffer[32];
|
// uint8_t buffer[32];
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
int length = USBCDC_ReceiveData(buffer, sizeof(buffer));
|
// int length = USBCDC_ReceiveData(buffer, sizeof(buffer));
|
||||||
if(length)
|
// if(length)
|
||||||
{
|
// {
|
||||||
USBCDC_SendData(buffer, length);
|
// USBCDC_SendData(buffer, length);
|
||||||
}
|
// }
|
||||||
// __WFI();
|
// __WFI();
|
||||||
|
HPGL_Poll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,7 @@
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
|
#include "hpgl.h"
|
||||||
|
#include "pwm_output.h"
|
||||||
|
|
||||||
int main(void);
|
int main(void);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Port A
|
// Port A
|
||||||
|
#define PIN_OUTPUT_X 8 // PA8 - TIM1_CH1
|
||||||
|
#define PIN_OUTPUT_Y 9 // PA9 - TIM1_CH2
|
||||||
#define PIN_USB_DM 11 // PA11 - USB_DM
|
#define PIN_USB_DM 11 // PA11 - USB_DM
|
||||||
#define PIN_USB_DP 12 // PA12 - USB_DP
|
#define PIN_USB_DP 12 // PA12 - USB_DP
|
||||||
// #define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+
|
// #define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+
|
||||||
|
|
|
||||||
163
stm32f103c8t6/src/pwm_output.c
Normal file
163
stm32f103c8t6/src/pwm_output.c
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include "stm32f1xx.h"
|
||||||
|
#include "pwm_output.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "pinning.h"
|
||||||
|
#include "ownership.h"
|
||||||
|
|
||||||
|
MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_X);
|
||||||
|
MODULE_OWNS_PIN(GPIOA, PIN_OUTPUT_Y);
|
||||||
|
|
||||||
|
static HPGL_Movement_t Output_Buffer[CONFIG_BUFFER_MOVEMENTS];
|
||||||
|
static const HPGL_Movement_t *Output_BufferRead = Output_Buffer;
|
||||||
|
static HPGL_Movement_t *Output_BufferWrite = Output_Buffer;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int x;
|
||||||
|
unsigned int y;
|
||||||
|
} Output_Coordinate_t;
|
||||||
|
|
||||||
|
static Output_Coordinate_t Output_CurrentPoint = {0, 0};
|
||||||
|
static Output_Coordinate_t Output_TargetPoint = {0, 0};
|
||||||
|
static int Output_CurrentVelocity = 10;
|
||||||
|
|
||||||
|
bool Output_EnqueueMovement(HPGL_Movement_t movement)
|
||||||
|
{
|
||||||
|
int buffer_space = Output_BufferRead - Output_BufferWrite - 1;
|
||||||
|
if(buffer_space < 0)
|
||||||
|
{
|
||||||
|
buffer_space += CONFIG_BUFFER_MOVEMENTS;
|
||||||
|
}
|
||||||
|
if(buffer_space == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(movement.x > OUTPUT_COORDINATE_LIMIT)
|
||||||
|
{
|
||||||
|
movement.x = OUTPUT_COORDINATE_LIMIT;
|
||||||
|
}
|
||||||
|
if(movement.y > OUTPUT_COORDINATE_LIMIT)
|
||||||
|
{
|
||||||
|
movement.y = OUTPUT_COORDINATE_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(Output_BufferWrite, &movement, sizeof(HPGL_Movement_t));
|
||||||
|
Output_BufferWrite++;
|
||||||
|
if(Output_BufferWrite >= Output_Buffer + CONFIG_BUFFER_MOVEMENTS)
|
||||||
|
{
|
||||||
|
Output_BufferWrite = Output_Buffer;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Output_FetchNextPoint(void)
|
||||||
|
{
|
||||||
|
if(Output_BufferRead == Output_BufferWrite)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HPGL_Movement_t *movement = Output_BufferRead;
|
||||||
|
Output_TargetPoint.x = movement->x;
|
||||||
|
Output_TargetPoint.y = movement->y;
|
||||||
|
// TODO: Handle pen state
|
||||||
|
|
||||||
|
Output_BufferRead++;
|
||||||
|
if(Output_BufferRead >= Output_Buffer + CONFIG_BUFFER_MOVEMENTS)
|
||||||
|
{
|
||||||
|
Output_BufferRead = Output_Buffer;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Output_ApproximateLength(int dx, int dy)
|
||||||
|
{
|
||||||
|
if(dx < 0)
|
||||||
|
{
|
||||||
|
dx = -dx;
|
||||||
|
}
|
||||||
|
if(dy < 0)
|
||||||
|
{
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approximate vector length with alpha max plus beta min algorithm
|
||||||
|
if(dx < dy)
|
||||||
|
{
|
||||||
|
return dy + dx / 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return dx + dy / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Output_Position()
|
||||||
|
{
|
||||||
|
uint16_t compare_x = OUTPUT_PWM_OFFSET + Output_CurrentPoint.x;
|
||||||
|
uint16_t compare_y = OUTPUT_PWM_OFFSET + Output_CurrentPoint.y;
|
||||||
|
|
||||||
|
TIM1->CCR1 = compare_x;
|
||||||
|
TIM1->CCR2 = compare_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output_Tick(void)
|
||||||
|
{
|
||||||
|
int step_length = Output_CurrentVelocity;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Compute distance to current target point
|
||||||
|
int diff_x = (int)(Output_TargetPoint.x) - (int)(Output_CurrentPoint.x);
|
||||||
|
int diff_y = (int)(Output_TargetPoint.y) - (int)(Output_CurrentPoint.y);
|
||||||
|
int length_ahead = Output_ApproximateLength(diff_x, diff_y);
|
||||||
|
if(step_length <= length_ahead)
|
||||||
|
{
|
||||||
|
// Move closer to current target point
|
||||||
|
Output_CurrentPoint.x += diff_x * step_length / length_ahead;
|
||||||
|
Output_CurrentPoint.y += diff_y * step_length / length_ahead;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current target point is not far enough away to keep velocity
|
||||||
|
step_length -= length_ahead;
|
||||||
|
if(!Output_FetchNextPoint())
|
||||||
|
{
|
||||||
|
// No more points in queue, stop here
|
||||||
|
Output_CurrentPoint = Output_TargetPoint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Output_Position();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Output_Init(void)
|
||||||
|
{
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
||||||
|
|
||||||
|
GPIOA->CRH = (GPIOA->CRH
|
||||||
|
& ~(0xf << (4 * PIN_OUTPUT_X - 32))
|
||||||
|
& ~(0xf << (4 * PIN_OUTPUT_Y - 32)))
|
||||||
|
| (0xa << (4 * PIN_OUTPUT_X - 32)) // AF output, 2 MHz
|
||||||
|
| (0xa << (4 * PIN_OUTPUT_Y - 32)) // AF output, 2 MHz
|
||||||
|
;
|
||||||
|
|
||||||
|
TIM1->CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1
|
||||||
|
| TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1;
|
||||||
|
TIM1->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E;
|
||||||
|
TIM1->BDTR = TIM_BDTR_MOE;
|
||||||
|
TIM1->ARR = (1 << OUTPUT_PWM_RESOLUTION) - 1;
|
||||||
|
TIM1->DIER = TIM_DIER_UIE;
|
||||||
|
TIM1->CR1 = TIM_CR1_CEN;
|
||||||
|
NVIC_EnableIRQ(TIM1_UP_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIM1_UP_IRQHandler(void)
|
||||||
|
{
|
||||||
|
Output_Tick();
|
||||||
|
|
||||||
|
TIM1->SR &= ~TIM_SR_UIF;
|
||||||
|
}
|
||||||
12
stm32f103c8t6/src/pwm_output.h
Normal file
12
stm32f103c8t6/src/pwm_output.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hpgl.h"
|
||||||
|
|
||||||
|
#define OUTPUT_PWM_RESOLUTION 15 // In bits
|
||||||
|
#define OUTPUT_PWM_OFFSET 300 // Minimum value
|
||||||
|
|
||||||
|
#define OUTPUT_RESOLUTION 14 // In bits
|
||||||
|
#define OUTPUT_COORDINATE_LIMIT ((1 << OUTPUT_RESOLUTION) - 1)
|
||||||
|
|
||||||
|
void Output_Init(void);
|
||||||
|
bool Output_EnqueueMovement(HPGL_Movement_t movement);
|
||||||
|
|
@ -148,11 +148,12 @@ void USBCDC_HandleDataOut(void)
|
||||||
|
|
||||||
// Determine the free space in the ring buffer and if another packet will
|
// Determine the free space in the ring buffer and if another packet will
|
||||||
// fit in
|
// fit in
|
||||||
int ring_buffer_space = USBCDC_RXBufferRead - USBCDC_RXBufferWrite - 1;
|
int ring_buffer_space = USBCDC_RXBufferRead - USBCDC_RXBufferWrite;
|
||||||
if(ring_buffer_space < 0)
|
if(ring_buffer_space < 0)
|
||||||
{
|
{
|
||||||
ring_buffer_space += CONFIG_USB_RINGBUFFER_SIZE;
|
ring_buffer_space += CONFIG_USB_RINGBUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
ring_buffer_space -= 1;
|
||||||
if(ring_buffer_space >= USBCDC_ENDPOINT_SIZE)
|
if(ring_buffer_space >= USBCDC_ENDPOINT_SIZE)
|
||||||
{
|
{
|
||||||
// Set EP3 ready for the next packet only when there is enough space in
|
// Set EP3 ready for the next packet only when there is enough space in
|
||||||
|
|
@ -201,6 +202,10 @@ int USBCDC_ReceiveData(void *buffer, int length)
|
||||||
if(USBCDC_RXSuspended)
|
if(USBCDC_RXSuspended)
|
||||||
{
|
{
|
||||||
int ring_buffer_free = USBCDC_RXBufferRead - USBCDC_RXBufferWrite - 1;
|
int ring_buffer_free = USBCDC_RXBufferRead - USBCDC_RXBufferWrite - 1;
|
||||||
|
if(ring_buffer_free < 0)
|
||||||
|
{
|
||||||
|
ring_buffer_free += CONFIG_USB_RINGBUFFER_SIZE;
|
||||||
|
}
|
||||||
if(ring_buffer_free >= USBCDC_ENDPOINT_SIZE)
|
if(ring_buffer_free >= USBCDC_ENDPOINT_SIZE)
|
||||||
{
|
{
|
||||||
USB_SetEPRXStatus(&(USB->EP3R), USB_EP_RX_VALID);
|
USB_SetEPRXStatus(&(USB->EP3R), USB_EP_RX_VALID);
|
||||||
|
|
@ -211,6 +216,38 @@ int USBCDC_ReceiveData(void *buffer, int length)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int USBCDC_ReceiveByte()
|
||||||
|
{
|
||||||
|
if(USBCDC_RXBufferRead == USBCDC_RXBufferWrite)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uint8_t byte = *USBCDC_RXBufferRead;
|
||||||
|
USBCDC_RXBufferRead++;
|
||||||
|
if(USBCDC_RXBufferRead >= USBCDC_RXBuffer + CONFIG_USB_RINGBUFFER_SIZE)
|
||||||
|
{
|
||||||
|
USBCDC_RXBufferRead = USBCDC_RXBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If receiving has been suspended because the ring buffer is too full,
|
||||||
|
// resume if there is now enough space for another packet
|
||||||
|
if(USBCDC_RXSuspended)
|
||||||
|
{
|
||||||
|
int ring_buffer_free = USBCDC_RXBufferRead - USBCDC_RXBufferWrite - 1;
|
||||||
|
if(ring_buffer_free < 0)
|
||||||
|
{
|
||||||
|
ring_buffer_free += CONFIG_USB_RINGBUFFER_SIZE;
|
||||||
|
}
|
||||||
|
if(ring_buffer_free >= USBCDC_ENDPOINT_SIZE)
|
||||||
|
{
|
||||||
|
USB_SetEPRXStatus(&(USB->EP3R), USB_EP_RX_VALID);
|
||||||
|
USBCDC_RXSuspended = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
// Build a USB in packet out of data from the transmit ring buffer and mark it
|
// Build a USB in packet out of data from the transmit ring buffer and mark it
|
||||||
// valid for the host to fetch it
|
// valid for the host to fetch it
|
||||||
static void USBCDC_BuildInPacket(void)
|
static void USBCDC_BuildInPacket(void)
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,7 @@ void USBCDC_SendData(const void *data, int length);
|
||||||
// Writes received data into a buffer. Returns the number of bytes written into
|
// Writes received data into a buffer. Returns the number of bytes written into
|
||||||
// the buffer.
|
// the buffer.
|
||||||
int USBCDC_ReceiveData(void *buffer, int length);
|
int USBCDC_ReceiveData(void *buffer, int length);
|
||||||
|
|
||||||
|
// Reads a single byte from the receive buffer. If none are available, this
|
||||||
|
// function returns -1.
|
||||||
|
int USBCDC_ReceiveByte(void);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue