/****************************************************************************/
/* Copyright 2002 MBARI							*/
/****************************************************************************/
/* Summary  : Main Routine for OASIS Mooring Controller                     */
/* Filename : oasis.c                                                       */
/* Author   : Robert Herlien (rah)					    */
/* Project  : OASIS Mooring Replacement (OASIS3)			*/
/* Revision : 0.1							*/
/* Created  : 10/14/2002						*/
/*									    */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*									    */
/****************************************************************************/
/* Modification History:						    */
/* 10oct2002 rah - created from OASIS oasis.c				*/
/****************************************************************************/

#include	<mbariTypes.h>		/* MBARI type definitions	    */
#include	<mbariConst.h>		/* MBARI constants		    */
#include	<cfxbios.h>		// Persistor BIOS and I/O Definitions
#include	<cfxpico.h>		// Persistor PicoDOS Definitions
#include	<stdio.h>
#include	<string.h>
#include	<fat.h>

#define CPU_CLOCK	7360L
#define DRIVE		DSD_FIRST_DEV

MLocal Byte	buffer[512];
MLocal Fat16BR	bootRec;

MLocal Nat16	swapWord(Nat16 wrd);
MLocal Nat32	swapLong(Nat32 lng);


/************************************************************************/
/* Function    : swapWord						*/
/* Purpose     : Swap bytes of a word					*/
/* Inputs      : Word							*/
/* Outputs     : Word							*/
/************************************************************************/
MLocal Nat16	swapWord(Nat16 wrd)
{
  return( ((wrd & 0xff) << 8) | ((wrd >>8) & 0xff) );

} /* swapWord() */


/************************************************************************/
/* Function    : swapLong						*/
/* Purpose     : Swap bytes of a long					*/
/* Inputs      : Word							*/
/* Outputs     : Word							*/
/************************************************************************/
MLocal Nat32	swapLong(Nat32 lng)
{
  return( ((Nat32)swapWord((Nat16)(lng & 0xffff)) << 16) |
	   swapWord((Nat16)((lng >> 16) & 0xffff)) );

} /* swapLong() */


/************************************************************************/
/* Function    : main							*/
/* Purpose     : Main entry point					*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/* Comments    : Never returns						*/
/************************************************************************/
int main( int argc, char **argv)
{
#pragma unused (argc, argv)
  Nat32		sectors, longClusters;
  Byte		sectorsPerCluster;
  Nat16		bytesPerSect, rsvdSects, sectsPerFat, dirEntries;
  Nat16		FAT1Sector, FAT2Sector, dirSector, dirSects, totClusters;
  Nat16		FATEntriesPerSect, dataSector;
  Nat16		val, i;

  BIOSInit();
  TMGSetSpeed(CPU_CLOCK);
  // Identify the progam and build
  printf("\nProgram: %s: %s %s \n", __FILE__, __DATE__, __TIME__);
  // Identify the device and its firmware
  printf("Persistor CF%d SN:%ld   BIOS:%d.%d   PicoDOS:%d.%d\n", CFX,
	 BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
	 BIOSGVT.PICOVersion, BIOSGVT.PICORelease);
	
  printf("OASIS format program\n\n");
  DSDReadSectors(DRIVE, 0L, buffer, 1);
  memcpy(&bootRec, buffer, sizeof(bootRec));
  sectors = swapLong(bootRec.numberSectors);
  rsvdSects = swapWord(bootRec.reservedSectors);
  bytesPerSect = (bootRec.bytesPerSect_hi << 8) + bootRec.bytesPerSect_low;
  sectorsPerCluster = bootRec.sectorsPerCluster;
  sectsPerFat = swapWord(bootRec.sectorsPerFat);
  dirEntries = (bootRec.rootDirEntries_hi << 8) + bootRec.rootDirEntries_low;
  FAT1Sector = rsvdSects;
  FAT2Sector = FAT1Sector + sectsPerFat;
  dirSector = FAT2Sector + sectsPerFat;
  dirSects = (Nat16)((((Nat32)dirEntries * DIR_ENTRY_SIZE) + bytesPerSect - 1)
		     / bytesPerSect);
  dataSector = dirSector + dirSects;
  totClusters = (sectors - dataSector)/(Nat16)sectorsPerCluster + 2;

  printf("Sects = %lu, rsvd sects = %u, bytes/sect = %u\n",
	 sectors, rsvdSects, bytesPerSect);
  printf("Sects/cluster = %u, sects/FAT = %u, Root dir entries = %u\n", 
	 (Nat16)sectorsPerCluster, sectsPerFat, dirEntries);
  printf("Start of FAT1 = %u, Start of FAT2 = %u, Start of directory = %u\n",
	 FAT1Sector, FAT2Sector, dirSector);
  printf("Total Clusters = %u, Number Dir sectors = %u\n", totClusters, dirSects);

  printf("\nNew sectors/cluster:  ");
  if ((scanf("%u", &val) < 1) || (val < 2) || (val > 128))
  {
    printf("\nBad input value\n");
    return(0);
  }

  sectorsPerCluster = (Byte)val;

  printf("\nNew #Root Directory Entries:  ");
  if ((scanf("%u", &val) < 1) || (val < 256) || (val > 16384))
  {
    printf("\nBad input value\n");
    return(0);
  }

  dirEntries = val;
  dirSects = (Nat16)((((Nat32)dirEntries * DIR_ENTRY_SIZE) + bytesPerSect - 1)
		     / bytesPerSect);

  FATEntriesPerSect = bytesPerSect / sizeof(Nat16);
  longClusters = (sectors - dirSects)/sectorsPerCluster;
  if (longClusters > 65535L)
  {
    printf("\n\nCluster size too small\n");
    return(1);
  }

  totClusters = (sectors - dirSects)/sectorsPerCluster;
  sectsPerFat = (totClusters + FATEntriesPerSect - 1) / FATEntriesPerSect;
  totClusters = (sectors - dirSects - 2 * sectsPerFat)/sectorsPerCluster;
  sectsPerFat = (totClusters + FATEntriesPerSect - 1) / FATEntriesPerSect;
  FAT1Sector = rsvdSects;
  FAT2Sector = FAT1Sector + sectsPerFat;
  dirSector = FAT2Sector + sectsPerFat;
  dataSector = dirSector + dirSects;
  totClusters = (sectors - dataSector)/(Nat16)sectorsPerCluster + 2;

  printf("\n\nSects = %lu, rsvd sects = %u, bytes/sect = %u\n",
	 sectors, rsvdSects, bytesPerSect);
  printf("Sects/cluster = %u, sects/FAT = %u, Root dir entries = %u\n", 
	 (Nat16)sectorsPerCluster, sectsPerFat, dirEntries);
  printf("Start of FAT1 = %u, Start of FAT2 = %u, Start of directory = %u\n",
	 FAT1Sector, FAT2Sector, dirSector);
  printf("Total Clusters = %u, Number Dir sectors = %u\n", totClusters, dirSects);

  bootRec.sectorsPerCluster = sectorsPerCluster;
  bootRec.sectorsPerFat = swapWord(sectsPerFat);
  DSDWriteSectors(DRIVE, 0L, &bootRec, 1);

  memset(buffer, 0, sizeof(buffer));
  buffer[0] = 0xf8;
  buffer[1] = 0xff;
  buffer[2] = 0xff;
  buffer[3] = 0xff;
  DSDWriteSectors(DRIVE, (Nat32)(FAT1Sector), buffer, 1);
  DSDWriteSectors(DRIVE, (Nat32)(FAT2Sector), buffer, 1);

  memset(buffer, 0, sizeof(buffer));
  for (i = 1; i < sectsPerFat; i++ )
  {
    DSDWriteSectors(DRIVE, (Nat32)(FAT1Sector + i), buffer, 1);
    DSDWriteSectors(DRIVE, (Nat32)(FAT2Sector + i), buffer, 1);
  }

  for (i = 0; i < dirSects; i++ )
    DSDWriteSectors(DRIVE, (Nat32)(dirSector + i), buffer, 1);

  return(0);

}	//____ main() ____//
