#include "commlib-head.h"

#ifdef PLATFORM_HC11
#ifndef PLATFORM_SLG
#include <hidef.h>
#include <stddef.h>
#include <stdtypes.h>
#include <Terminal.h>
#include <startup.h>
#endif /* ifdef PLATFORM_SLG */
#endif /* ifdef PLATFORM_HC11 */
#include <stdio.h>
#include <assert.h>



void pc_send_packet(unsigned char EventID,
		    unsigned char DataLength,
		    const unsigned char *Data) {
  unsigned char i;
  unsigned char checksum;

  /* write EventID */
  TERM_Write(EventID);
  checksum = EventID;

  /* write DataLength */
  TERM_Write(DataLength);
  checksum += DataLength;

  /* write payload */
  for(i=0; i<DataLength; ++i) {
    TERM_Write(Data[i]);
    checksum += Data[i];
  }

  /* write checksum */
  TERM_Write(checksum);
} /* pc_send_packet */

unsigned char pc_recv_packet(pcdata *pkt) {
  unsigned char i;
  unsigned char data;
  unsigned char checksum;
  unsigned char DataLength;

  /* read EventID */
  data = TERM_Read();
  pkt->EventID = data;
  checksum = data;

  /* read data length */
  data = TERM_Read();
  DataLength = data;
  pkt->DataLength = data;
  checksum += data;

  /* read payload */
  for(i=0; i<DataLength; ++i) {
    data = TERM_Read();
    pkt->Data[i] = data;
    checksum += data;
  }

  /* read checksum */
  data = TERM_Read();
  pkt->Data[DataLength] = data;
  checksum -= data;

  return checksum;
} /* pc_recv_packet */

unsigned char pc_recv_packet_args(unsigned char *EventID,
			 unsigned char *DataLength,
			 unsigned char *Data) {
  unsigned char i;
  unsigned char dataword;
  unsigned char checksum;

  /* read EventID */
  dataword = TERM_Read();
  *EventID = dataword;
  checksum = dataword;

  /* read data length */
  dataword = TERM_Read();
  *DataLength = dataword;
  checksum += dataword;

  /* read payload */
  for(i=0; i<*DataLength; ++i) {
    dataword = TERM_Read();
    Data[i] = dataword;
    checksum += dataword;
  }

  /* read checksum */
  dataword = TERM_Read();
  Data[*DataLength] = dataword;
  checksum -= dataword;

  return checksum;
} /* pc_recv_packet_args */

void pc_debug(char *message) {
  int i;
  int len=0;
  unsigned char checksum;
  pcdata ack; /* stores the ack */
  
  /* get strlen(message) */
  for(i=0; i<256 && message[i] != '\0'; ++i)
    ++len;

  /* write EventID */
  TERM_Write(PC_EVENT_DEBUG_MESSAGE);
  checksum = PC_EVENT_DEBUG_MESSAGE;

  /* write DataLength */
  TERM_Write(len);
  checksum += (unsigned char)len; /* XXX does this work? */

  /* write payload */
  for(i=0; i<len; ++i) {
    TERM_Write(message[i]);
    checksum += message[i];
  }

  /* write checksum */
  TERM_Write(checksum);

  pc_recv_packet(&ack);
  assert(ack.EventID == PC_EVENT_ACK);
} /* pc_debug */


void pc_fopen(const char *filename, const char *mode) {
  pcdata response;

  do {
    pc_send_packet(PC_EVENT_OPEN_FILE,0,NULL);
    pc_recv_packet(&response);

    if(response.EventID == PC_EVENT_NACK)
      pc_debug("received nack");
  } while (response.EventID != PC_EVENT_ACK);
} /* pc_fopen */



void pc_fclose(void *stream) {
  /* XXX  um, do nothing? */
  pc_debug("I'm closing a file. Not that you care or anything.");
} /* pc_fclose */

void pc_fread(unsigned char *ptr,
	      unsigned int size,
	      unsigned int  nitems,
	      void *stream) {
  unsigned int i,j;
  signed long size_sent; /* have to send 32-bit two's-complement, not uchar */
  pcdata pkt;
  unsigned char checksum;

  for(i=0; i<nitems; ++i) {
    for(j=(size<255 ? size : 255); j<size; j += 256) {
      size_sent = j % 256;
	pc_send_packet(PC_EVENT_READ_MP3_BYTES,
		       sizeof(signed long),
		       (char*)&size_sent);
      do {
	checksum = pc_recv_packet_args(&(pkt.EventID),
				       &(pkt.DataLength),
				       ptr + i*size + j);
	if(checksum==0) {
	  pc_send_packet(PC_EVENT_ACK,0,NULL);
	} else {
	  pc_send_packet(PC_EVENT_RESEND,0,NULL);
	}
      } while(checksum != 0);
    } /* for j */
  } /* for i */
} /* pc_fread */

void pc_fwrite(const char *ptr, size_t size, size_t nitems, void *stream) {
  int i,j;
  unsigned char size_sent;
  pcdata response;

  for(i=0; i<nitems; ++i) {
    for(j=(size<255)?size:255; j<size; j += 256) {
      size_sent = j % 256;

      do {
	pc_send_packet(PC_EVENT_RECEIVE_DECODED_BYTES,
		       size_sent, ptr + i*size + j);
	pc_recv_packet(&response);
      } while(response.EventID==PC_EVENT_RESEND);
    } /* for j */
  } /* for i */
} /* pc_fwrite */

/* pc_fseek is used only for fseeking output */
void pc_fseek(void *stream, long offset, int whence) {
  pcdata response;

  /* XXX this is slow; remove it: */
  if(whence != SEEK_SET) {
    pc_debug("pc_fseek got non-SEEK_SET whence");
  }

  do {
    pc_send_packet(PC_EVENT_OUT_FILE_SEEK,sizeof(offset),(char*)&offset);
    pc_recv_packet(&response);
  } while(response.EventID==PC_EVENT_RESEND);

} /* pc_fseek */

