/* "avrstick USBdisk example"   */
/*                              */
/* This demo implements an USB  */
/* virtual COM port and an USB  */
/* MassStorage device.          */
/* (without virtual filesystem) */

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include <string.h>
#include <stdio.h>

#include <stdbool.h>
#include <stdint.h>

#if (F_CPU != 32000000)
#warning clock should better be 32MHz - USB needs it
#endif


/* initialize all the USB (terminal + disk)
 *  - also switches to 32MHz
 *  - enables medium priority interrupts
 *  - also enables global interrupts 
 */
extern void USBInit(void);

/* process the USB */
extern void USBPoll(void);

/* the I/O steam of the USB terminal */
extern FILE *USBtty0;

#define USBdisk_sectorSize 512
/* Global number of 512 byte sectors the MassStorage
 * disk should identify itself with
 * Best initialized before "USBInit()".
 */
extern uint32_t USBdisk_sectorCount;

/* Global information about the type of the media
 * Best initialized before "USBInit()".
 */
extern bool USBdisk_readOnly;




static volatile unsigned long abstinent_reads = 0;
static volatile unsigned long abstinent_writes = 0;

int main(void)
{
    USBdisk_sectorCount	= 256; /* = 128 KiB */
    USBdisk_readOnly	= true; /* forbid write */

    /* Init the USB (and clock + interrupts) */
    USBInit();

    for (;;)
    {
	/* Must throw away unused bytes from the host */
	int c = fgetc(USBtty0);

	/* simple demo: implement an echo */
	if (!(c<0)) {
	    fprintf_P(USBtty0, PSTR("%3lu sectors read, %3lu writes ignored,    key pressed: %c\r\n"),
		      abstinent_reads, abstinent_writes, c);
	    abstinent_reads=0;
	    abstinent_writes=0;
	}
	
	USBPoll();
    }
}


/* "USBdisk_CALLBACK_readSector" is called internally by the USB/SCSI stack.
 * Its purpose is to:
 * (1) read a sector "in_sectorNumber" (starting at 0),
 * (2) put the secotors content into "out_sectordata"
 * (3) return the number of bytes read - usually 512 (USBdisk_sectorSize).
 */
int16_t USBdisk_CALLBACK_readSector(uint8_t out_sectordata[USBdisk_sectorSize], const uint32_t in_sectorNumber)
{
  /* increase the read counter */
  abstinent_reads++;
  /* "fill" the sector with some data, make it depend on "in_sectorNumber" to see the different sectors */
  memset(&out_sectordata[0], ~(in_sectorNumber & 0xff), USBdisk_sectorSize);
  return USBdisk_sectorSize;
}


/* "USBdisk_CALLBACK_writeSector" is called internally by the USB/SCSI stack.
 * Its purpose is to:
 * (1) put the content "in_sectordata" on the media at sector "in_sectorNumber"
 * (2) return the number of bytes written - usually 512 (USBdisk_sectorSize).
 */
int16_t USBdisk_CALLBACK_writeSector(uint8_t in_sectordata[USBdisk_sectorSize], const uint32_t in_sectorNumber)
{
  /* increase the write counter */
  abstinent_writes++;
  /* at the moment simply ignore the write - in case of readOnly it shouldn't be called anyway */
  return USBdisk_sectorSize;
}