/*-------------------------------------------------------------------- * TITLE: Plasma Uart Driver * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) * DATE CREATED: 12/31/05 * FILENAME: uart.c * PROJECT: Plasma CPU core * COPYRIGHT: Software placed into the public domain by the author. * Software 'as is' without warranty. Author liable for nothing. * DESCRIPTION: * Plasma Uart Driver *--------------------------------------------------------------------*/ #define NO_ELLIPSIS2 #include "plasma.h" #include "rtos.h" #ifndef NO_PACKETS #define SUPPORT_DATA_PACKETS #endif #define BUFFER_WRITE_SIZE 128 #define BUFFER_READ_SIZE 128 #define BUFFER_PRINTF_SIZE 1024 #undef UartPrintf void UartPrintfCritical(const char *format, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7); typedef struct Buffer_s { uint8 *data; int size; volatile int read, write; volatile int pendingRead, pendingWrite; OS_Semaphore_t *semaphoreRead, *semaphoreWrite; } Buffer_t; static Buffer_t *WriteBuffer, *ReadBuffer; static OS_Semaphore_t *SemaphoreUart; static char PrintfString[BUFFER_PRINTF_SIZE]; //Used in UartPrintf #ifdef SUPPORT_DATA_PACKETS //For packet processing [0xff lengthMSB lengthLSB checksum data] static PacketGetFunc_t UartPacketGet; static uint8 *PacketCurrent; static uint32 UartPacketSize; static uint32 UartPacketChecksum, Checksum; static OS_MQueue_t *UartPacketMQueue; static uint32 PacketBytes, PacketLength; static uint32 UartPacketOutLength, UartPacketOutByte; int CountOk, CountError; #endif static uint8 *UartPacketOut; /******************************************/ Buffer_t *BufferCreate(int size) { Buffer_t *buffer; buffer = (Buffer_t*)OS_HeapMalloc(NULL, sizeof(Buffer_t) + size); if(buffer == NULL) return NULL; buffer->data = (uint8*)(buffer + 1); buffer->read = 0; buffer->write = 0; buffer->size = size; buffer->pendingRead = 0; buffer->pendingWrite = 0; buffer->semaphoreRead = OS_SemaphoreCreate("BufferRead", 0); buffer->semaphoreWrite = OS_SemaphoreCreate("BufferWrite", 0); return buffer; } void BufferWrite(Buffer_t *buffer, int value, int pend) { int writeNext; writeNext = buffer->write + 1; if(writeNext >= buffer->size) writeNext = 0; //Check if room for value if(writeNext == buffer->read) { if(pend == 0) return; ++buffer->pendingWrite; OS_SemaphorePend(buffer->semaphoreWrite, OS_WAIT_FOREVER); } buffer->data[buffer->write] = (uint8)value; buffer->write = writeNext; if(buffer->pendingRead) { --buffer->pendingRead; OS_SemaphorePost(buffer->semaphoreRead); } } int BufferRead(Buffer_t *buffer, int pend) { int value; //Check if empty buffer if(buffer->read == buffer->write) { if(pend == 0) return 0; ++buffer->pendingRead; OS_SemaphorePend(buffer->semaphoreRead, OS_WAIT_FOREVER); } value = buffer->data[buffer->read]; if(++buffer->read >= buffer->size) buffer->read = 0; if(buffer->pendingWrite) { --buffer->pendingWrite; OS_SemaphorePost(buffer->semaphoreWrite); } return value; } /******************************************/ #ifdef SUPPORT_DATA_PACKETS static void UartPacketRead(uint32 value) { uint32 message[4]; if(PacketBytes == 0 && value == 0xff) { ++PacketBytes; } else if(PacketBytes == 1) { ++PacketBytes; PacketLength = value << 8; } else if(PacketBytes == 2) { ++PacketBytes; PacketLength |= value; if(PacketLength <= UartPacketSize) { if(PacketCurrent == NULL) PacketCurrent = UartPacketGet(); } else { PacketBytes = 0; } } else if(PacketBytes == 3) { ++PacketBytes; UartPacketChecksum = value; Checksum = 0; } else if(PacketBytes >= 4) { if(PacketCurrent) PacketCurrent[PacketBytes - 4] = (uint8)value; Checksum += value; ++PacketBytes; if(PacketBytes - 4 >= PacketLength) { if((uint8)Checksum == UartPacketChecksum) { //Notify thread that a packet has been received ++CountOk; message[0] = 0; message[1] = (uint32)PacketCurrent; message[2] = PacketLength; if(PacketCurrent) OS_MQueueSend(UartPacketMQueue, message); PacketCurrent = NULL; } else { ++CountError; //printf("E"); } PacketBytes = 0; } } } static int UartPacketWrite(void) { int value=0, i; uint32 message[4]; if(UartPacketOut) { if(UartPacketOutByte == 0) { value = 0xff; ++UartPacketOutByte; } else if(UartPacketOutByte == 1) { value = UartPacketOutLength >> 8; ++UartPacketOutByte; } else if(UartPacketOutByte == 2) { value = (uint8)UartPacketOutLength; ++UartPacketOutByte; } else if(UartPacketOutByte == 3) { value = 0; for(i = 0; i < (int)UartPacketOutLength; ++i) value += UartPacketOut[i]; value = (uint8)value; ++UartPacketOutByte; } else { value = UartPacketOut[UartPacketOutByte - 4]; ++UartPacketOutByte; if(UartPacketOutByte - 4 >= UartPacketOutLength) { //Notify thread that a packet has been sent message[0] = 1; message[1] = (uint32)UartPacketOut; UartPacketOut = 0; OS_MQueueSend(UartPacketMQueue, message); } } } return value; } #endif static void UartInterrupt(void *arg) { uint32 status, value, count=0; (void)arg; status = OS_InterruptStatus(); while(status & IRQ_UART_READ_AVAILABLE) { value = MemoryRead(UART_READ); #ifdef SUPPORT_DATA_PACKETS if(UartPacketGet && (value == 0xff || PacketBytes)) UartPacketRead(value); else #endif BufferWrite(ReadBuffer, value, 0); status = OS_InterruptStatus(); if(++count >= 16) break; } while(status & IRQ_UART_WRITE_AVAILABLE) { #ifdef SUPPORT_DATA_PACKETS if(UartPacketOut) { value = UartPacketWrite(); MemoryWrite(UART_WRITE, value); } else #endif if(WriteBuffer->read != WriteBuffer->write) { value = BufferRead(WriteBuffer, 0); MemoryWrite(UART_WRITE, value); } else { OS_InterruptMaskClear(IRQ_UART_WRITE_AVAILABLE); break; } status = OS_InterruptStatus(); } } void UartInit(void) { uint32 mask; SemaphoreUart = OS_SemaphoreCreate("Uart", 1); WriteBuffer = BufferCreate(BUFFER_WRITE_SIZE); ReadBuffer = BufferCreate(BUFFER_READ_SIZE); mask = IRQ_UART_READ_AVAILABLE | IRQ_UART_WRITE_AVAILABLE; OS_InterruptRegister(mask, UartInterrupt); OS_InterruptMaskSet(IRQ_UART_READ_AVAILABLE); } void UartWrite(int ch) { BufferWrite(WriteBuffer, ch, 1); OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); } uint8 UartRead(void) { return (uint8)BufferRead(ReadBuffer, 1); } void UartWriteData(uint8 *data, int length) { OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); while(length--) UartWrite(*data++); OS_SemaphorePost(SemaphoreUart); } void UartReadData(uint8 *data, int length) { OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); while(length--) *data++ = UartRead(); OS_SemaphorePost(SemaphoreUart); } void UartPrintf(const char *format, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { uint8 *ptr; #if 0 //Check for string "!m#~" to mask print statement static char moduleLevel[26]; if(format[0] == '!' && format[3] == '~') { int level = format[2] - '5'; if('a' <= format[1] && format[1] <= 'z') { if(level < moduleLevel[format[1] - 'a']) return; } else if('A' <= format[1] && format[1] <= 'Z') moduleLevel[format[1] - 'A'] = (char)level; format += 4; } #endif OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); sprintf(PrintfString, format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); ptr = (uint8*)PrintfString; while(*ptr) { if(*ptr == '\n') UartWrite('\r'); #ifdef SUPPORT_DATA_PACKETS if(*ptr == 0xff) *ptr = '@'; #endif UartWrite(*ptr++); } OS_SemaphorePost(SemaphoreUart); } void UartPrintfPoll(const char *format, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { uint8 *ptr; uint32 state; if(SemaphoreUart) OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); sprintf(PrintfString, format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); ptr = (uint8*)PrintfString; while(*ptr) { while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) ; state = OS_CriticalBegin(); if((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) && UartPacketOut == NULL) { MemoryWrite(UART_WRITE, *ptr++); } OS_CriticalEnd(state); } if(SemaphoreUart) OS_SemaphorePost(SemaphoreUart); } void UartPrintfCritical(const char *format, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { uint8 *ptr; uint32 state; state = OS_CriticalBegin(); sprintf(PrintfString, format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); ptr = (uint8*)PrintfString; while(*ptr) { while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) ; MemoryWrite(UART_WRITE, *ptr++); #ifdef SUPPORT_DATA_PACKETS if(UartPacketOut && UartPacketOutByte - 4 < UartPacketOutLength) { ++UartPacketOutByte; --ptr; } #endif } memset(PrintfString, 0, sizeof(PrintfString)); OS_CriticalEnd(state); } void UartPrintfNull(void) { } void UartScanf(const char *format, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) { int index = 0, ch; OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); for(;;) { ch = UartRead(); if(ch != '\b' || index) UartWrite(ch); if(ch == '\n' || ch == '\r') break; else if(ch == '\b') { if(index) { UartWrite(' '); UartWrite(ch); --index; } } else if(index < sizeof(PrintfString)) PrintfString[index++] = (uint8)ch; } UartWrite('\n'); PrintfString[index] = 0; sscanf(PrintfString, format, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); OS_SemaphorePost(SemaphoreUart); } #ifdef SUPPORT_DATA_PACKETS void UartPacketConfig(PacketGetFunc_t PacketGetFunc, int PacketSize, OS_MQueue_t *mQueue) { UartPacketGet = PacketGetFunc; UartPacketSize = PacketSize; UartPacketMQueue = mQueue; } void UartPacketSend(uint8 *data, int bytes) { UartPacketOutByte = 0; UartPacketOutLength = bytes; UartPacketOut = data; OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); } #else void UartPacketConfig(PacketGetFunc_t PacketGetFunc, int PacketSize, OS_MQueue_t *mQueue) { (void)PacketGetFunc; (void)PacketSize; (void)mQueue; } void UartPacketSend(uint8 *data, int bytes) { (void)data; (void)bytes; } #endif void Led(int mask, int value) { mask &= 0xff; MemoryWrite(GPIO0_CLEAR, mask); //clear MemoryWrite(GPIO0_OUT, value & mask); //set LEDs } /******************************************/ int puts(const char *string) { uint8 *ptr; OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); ptr = (uint8*)string; while(*ptr) { if(*ptr == '\n') UartWrite('\r'); UartWrite(*ptr++); } OS_SemaphorePost(SemaphoreUart); return 0; } int getch(void) { return BufferRead(ReadBuffer, 1); } int kbhit(void) { return ReadBuffer->read != ReadBuffer->write; } /******************************************/ #if 0 int LogArray[100], LogIndex; void LogWrite(int a) { if(LogIndex < sizeof(LogArray)/4) LogArray[LogIndex++] = a; } void LogDump(void) { int i; for(i = 0; i < LogIndex; ++i) { if(LogArray[i] > 0xfff) UartPrintfCritical("\n", 0,0,0,0,0,0,0,0); UartPrintfCritical("0x%x ", LogArray[i], 0,0,0,0,0,0,0); } LogIndex = 0; } #endif