opensend/Source/Serial.c

279 lines
7.2 KiB
C

/* *************************************
* Includes
* *************************************/
#include "Serial.h"
/* *************************************
* Defines
* *************************************/
#define SERIAL_BAUDRATE 115200
#define SERIAL_TX_RX_TIMEOUT 20000
#define SERIAL_RX_FIFO_EMPTY 0
#define SERIAL_TX_NOT_READY 0
/* *************************************
* Local Variables
* *************************************/
static volatile SERIAL_STATE SerialState;
static volatile size_t bytesRead;
static volatile uint32_t initPC_Address;
static volatile uint32_t RAMDest_Address;
static volatile size_t ExeSize;
static volatile size_t totalBytes;
static volatile size_t exeBytesRead;
static volatile bool serial_busy;
/* *************************************
* Local Prototypes
* *************************************/
void ISR_Serial(void)
{
enum
{
SERIAL_BG_X0 = 0,
SERIAL_BG_X1 = X_SCREEN_RESOLUTION - SERIAL_BG_X0,
SERIAL_BG_X2 = SERIAL_BG_X0,
SERIAL_BG_X3 = SERIAL_BG_X1,
SERIAL_BG_Y0 = 0,
SERIAL_BG_Y1 = SERIAL_BG_Y0,
SERIAL_BG_Y2 = Y_SCREEN_RESOLUTION - SERIAL_BG_Y0,
SERIAL_BG_Y3 = SERIAL_BG_Y2,
SERIAL_BG_R = 0,
SERIAL_BG_G = NORMAL_LUMINANCE,
SERIAL_BG_B = NORMAL_LUMINANCE,
};
static GsGPoly4 SerialBg = { .x[0] = SERIAL_BG_X0,
.x[1] = SERIAL_BG_X1,
.x[2] = SERIAL_BG_X2,
.x[3] = SERIAL_BG_X3,
.y[0] = SERIAL_BG_Y0,
.y[1] = SERIAL_BG_Y1,
.y[2] = SERIAL_BG_Y2,
.y[3] = SERIAL_BG_Y3,
.r[0] = 0,
.r[1] = 0,
.r[2] = SERIAL_BG_R,
.r[3] = SERIAL_BG_R,
.g[0] = 0,
.g[1] = 0,
.g[2] = SERIAL_BG_G,
.g[3] = SERIAL_BG_G,
.b[0] = 0,
.b[1] = 0,
.b[2] = SERIAL_BG_B,
.b[3] = SERIAL_BG_B, };
enum
{
SERIAL_STATE_TEXT_X = 148,
SERIAL_STATE_TEXT_Y = Y_SCREEN_RESOLUTION >> 1,
};
SystemIncreaseGlobalTimer();
if( (GfxIsGPUBusy() == true) || (SystemIsBusy() == true) )
{
return;
}
FontSetFlags(&SmallFont, FONT_BLEND_EFFECT | FONT_H_CENTERED);
if(SerialState == SERIAL_STATE_READING_EXE_DATA)
{
if(System1SecondTick() == false)
{
return;
}
else
{
FontSetFlags(&SmallFont, FONT_H_CENTERED);
}
}
GsSortGPoly4(&SerialBg);
switch(SerialState)
{
case SERIAL_STATE_INIT:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Serial initialization");
break;
case SERIAL_STATE_STANDBY:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Waiting for PC...");
break;
case SERIAL_STATE_WRITING_ACK:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Writing ACK");
break;
case SERIAL_STATE_READING_HEADER:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Reading data from header (%d/%d bytes)...", bytesRead, totalBytes);
break;
case SERIAL_STATE_READING_EXE_SIZE:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Getting PSX-EXE size from PC...");
break;
case SERIAL_STATE_READING_EXE_DATA:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Reading PSX-EXE data (%d/%d bytes)...", exeBytesRead, ExeSize);
break;
case SERIAL_STATE_WAITING_USER_INPUT:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Press any key to continue");
break;
case SERIAL_STATE_CLEANING_MEMORY:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Cleaning RAM before EXE data transfer...");
break;
default:
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Unknown state");
break;
}
FontSetFlags(&SmallFont, FONT_H_CENTERED);
if(RAMDest_Address != 0)
{
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 16, "RAM Dest address: 0x%08X", RAMDest_Address);
}
if(initPC_Address != 0)
{
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 32, "Init PC address: 0x%08X", initPC_Address);
}
if(ExeSize != 0)
{
FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 48, "PSX-EXE size: 0x%08X", ExeSize);
}
GfxDrawScene_Fast();
}
void SerialSetState(SERIAL_STATE state)
{
SerialState = state;
}
void SerialSetPCAddress(uint32_t addr)
{
initPC_Address = addr;
}
void SerialSetRAMDestAddress(uint32_t addr)
{
RAMDest_Address = addr;
}
void SerialSetExeSize(size_t size)
{
ExeSize = size;
}
void SerialInit(void)
{
uint8_t receivedBytes;
SetVBlankHandler(&ISR_Serial);
SerialState = SERIAL_STATE_INIT;
SIOStart(SERIAL_BAUDRATE);
SerialState = SERIAL_STATE_STANDBY;
// ------------------------------------
// Protocol description
// ------------------------------------
// 1. Wait to receive magic byte "99" from PC.
SerialRead(&receivedBytes, sizeof(uint8_t) );
if(receivedBytes != 99)
{
dprintf("Did not receive input magic number!\n");
return;
}
// 2. Send ACK (magic byte is ASCII code for 'b').
SerialState = SERIAL_STATE_WRITING_ACK;
SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t) );
}
void SerialSetExeBytesReceived(uint32_t bytes_read)
{
exeBytesRead += bytes_read;
}
bool SerialRead(uint8_t* ptrArray, size_t nBytes)
{
bytesRead = 0;
totalBytes = nBytes;
serial_busy = true;
if(nBytes == 0)
{
SerialWrite("SerialRead: invalid size %d\n", strnlen("SerialRead: invalid size %d\n", 30));
return false;
}
do
{
//uint16_t timeout = SERIAL_TX_RX_TIMEOUT;
while( (SIOCheckInBuffer() == SERIAL_RX_FIFO_EMPTY)); // Wait for RX FIFO not empty
*(ptrArray++) = SIOReadByte();
bytesRead++;
}while(--nBytes);
serial_busy = false;
return true;
}
bool SerialWrite(void* ptrArray, size_t nBytes)
{
serial_busy = true;
SystemDisableVBlankInterrupt();
if(nBytes == 0)
{
SerialWrite("SerialRead: invalid size %d\n", strnlen("SerialRead: invalid size %d\n", 30));
return false;
}
do
{
//uint16_t timeout = SERIAL_TX_RX_TIMEOUT;
while( (SIOCheckOutBuffer() == SERIAL_TX_NOT_READY)); // Wait for TX FIFO empty.
SIOSendByte(*(uint8_t*)ptrArray++);
}while(--nBytes);
SystemEnableVBlankInterrupt();
serial_busy = false;
return true;
}