/* For free support for VSIDE, please visit www.vsdsp-forum.com */

/*

This program redirects all UART console output to SPI1 so that you can
use the UART output privately.

	To use this program, include this in the beginning of your program:
	
		DLLIMPORT(uart_stdout) extern VO_FILE *uart_stdout;
		DLLIMPORT(uart_stderr) extern VO_FILE *uart_stderr;
	
	Then you can print to the uart with e.g. 
		
		fprintf(uart_stdout, "Hello, Uart!\n");

*/

#include <vo_stdio.h>
#include <volink.h>     // Linker directives like DLLENTRY
#include <apploader.h>  // RunLibraryFunction etc
#include <kernel.h>		// Kernel symbols
#include <stdlib.h>
#include <imem.h>
#include <audio.h>
#include "spi1con.h"

#define DEFAULT_SPI_UART_SPEED 460800

char *Spi1FileIdentify(register __i0 void *self, char *buf, u_int16 bufsize) {
  return "SPI1";
}

const FILEOPS spi1FileOperations = {
  (void*)CommonOkResultFunction,
  (void*)CommonOkResultFunction,
  (void*)CommonOkResultFunction,
  (void*)CommonOkResultFunction,
  Spi1ConsoleWrite
};
const SIMPLE_FILE spi1File = {
   __MASK_PRESENT|__MASK_OPEN|__MASK_READABLE|__MASK_WRITABLE|__MASK_FILE, 
   Spi1FileIdentify, &spi1FileOperations
};

VO_FILE *orig_stdout;
VO_FILE *orig_stderr;

extern u_int16 IntSpi1Vector;

//Redirect all output to spi1 and publish uartOut
void init(void) {
  /* Store original vectors */
  orig_stdout = vo_stdout;
  orig_stderr = vo_stderr;

  /* Set SPI1 interrupt vector */
  spiUart.origSpi1Vec = ReadIMem(0x20+INTV_SPI1);
  WriteIMem((0x20+INTV_SPI1), ReadIMem((u_int16)(&IntSpi1Vector)));
  /* Activate SPI1 interrupt */
  PERIP(INT_ENABLE0_HP) |= INTF_SPI1;

  /* Copy read and ioctl operations from stdin */
  spi1FileOperations.Read = stdin->op->Read;
  spi1FileOperations.Ioctl = stdin->op->Ioctl;

  /* Set default SPI UART speed */
  SetSPI1(DEFAULT_SPI_UART_SPEED);

  /* Present original stdout/stderr to user programs */
  AddSymbol("_uart_stdout", init, (u_int16)(vo_stdout)); //publish original stdout as uart_stdout
  AddSymbol("_uart_stderr", init, (u_int16)(vo_stderr)); //publish original stderr as uart_stderr

  /* Steal stdour/stderr pointers */
  vo_stdout = &spi1File; //point stdout to spi1file
  vo_stderr = &spi1File; //point stderr to spi1file
}

ioresult main(char *param) {
  u_int32 newUartSpeed = strtol(param, NULL, 0);
  if (newUartSpeed) {
    SetSPI1(newUartSpeed);
  }


#if 0
  {
    int i;
    u_int16 oT = (u_int16)ReadTimeCount();
    for (i=0; i<32; i++) {
      u_int16 nT = (u_int16)ReadTimeCount();
      printf("Previous HelloSPI #%2d took %3d ms!\n", i, nT-oT);
      oT = nT;
    }
  }
  while (spiUart.txWr != spiUart.txRd) Delay(1);
#endif
  
  return S_OK;
}

void fini(void) {
  PERIP(INT_ENABLE0_HP) &= ~INTF_SPI1;

  /* Remove our symbols */
  SymbolDeleteLib(init);
  
  /* Restore original vectors and pointers */
  WriteIMem((0x20+INTV_SPI1), spiUart.origSpi1Vec);
  vo_stdout = orig_stdout;
  vo_stderr = orig_stderr;
}
