/*  
  foxbone.c
  Application Test Code for FoxBone on FOX VHDL Board 
  (based on FoxBone protocol interface specifications rel 0.7)    
  For more info see: http://www.acmesystems.it/?id=120
  Author: Roberto Asquini & John Crispin
  Copyright (C) 2006 Acme Systems srl (http://www.acmesystems.it)
  
  This is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
    
  This example is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
    
  To have a copy of the GNU General Public License write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

// FOXBONE_BUS is on IOg[8-23]
// RESETN line is on Og3
// DATA_WRITE is on Og2
// DATA_READ is on Og1
// ADDRESS_WRITE is on Og4

// This example realizes a userspace implementation of a user interface for the FoxBone
// kernel driver between the Fox Board and the FOX VHDL Board.
// It uses a subset of the capabilities of the
// FoxBone protocol specifications rel. 0.7.
// It uses syscalls to speed up operations with respect to ioctl calls.

// the functions implemented are:
//   - reset of the bus with separate commands for asserting (low) and releasing the FoxBone Reset line.
//   - output of a specified data word on a specified 16 bit address of the FoxBone register space
//     structure inside the FOX VHDL FPGA
//   - input of a 16 bit word from a specified 16 bit address in the FoxBone register structure 
//     inside the FPGA.

// With simple scripts it is possible to test the input/output functions of the FoxBone.

#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "time.h"
#include "string.h"
#include "foxbone_userspace.h"
#include <linux/foxbone_syscalls.h>

void print_usage(void){
  printf("foxbone usage: foxbone command addr data\n"
     "valid commands:\n"
     "r = reset (addr = 0 or 1);\n"
     "o = output (addr = FoxBone address; data = data in output);\n"
     "f = output (addr = FoxBone address; data = data in output; \n"
     "                count = number of times to write);\n"
     "i = input (addr = FoxBone address);\n"
     "a = get the release info\n"        
     "Typical usages: \n"
     "foxbone r 1 (resets the foxbone hardware interface and peripherals)\n"
     "foxbone o 1000 55AA (output on the FoxBone address 0x1000 of the 0x55AA value word)\n"
     "foxbone f 1000 55AA 0A (output repeated 10 times (0x0a) on FoxBone address \n" 
     "                        0x1000 of the value 0x55AA:  0A hex = 10 decimal  )\n"
     "foxbone i 1000 (input a word from the FoxBone address 0x1000)\n");
};

// -----------------------------------------------------------------------------
// FoxBone_command
// -----------------------------------------------------------------------------
void FoxBone_command(int myargc, char **myargv) {
  int retval, addr=0, data=0, data2=0, i;
  unsigned int value;
  // minimal input validation
  if (myargc<2) {
    print_usage();
    return;
  }
  if (myargc > 2) {
    retval = sscanf(myargv[2],"%x", &addr);
  }
  if (myargc > 3) {
    retval = sscanf(myargv[3],"%x", &data);
  }
  if (myargc > 4) {
    retval = sscanf(myargv[4],"%x", &data2);
  }
  unsigned int bulk_data[10];
  
  switch ( myargv[1][0]) {
  case 'r':                                                                                           
    foxbonereset(1);                                                                                
    break;                                                                                          
  case 'o':                                                                                         
    foxbonewrite(addr, data);                                                                       
    printf("FoxBone output data 0x%4x on addr 0x%04x\n",data, addr);                          
    break;                                                                                          
  case 'i':                                                                                         
    value = foxboneread(addr);                                                                      
    printf("FoxBone input from addr 0x%04x: 0x%04x\n",addr, value);                           
    break;                                                                                          
  case 'f':                                                                                         
    foxbonebulkwrite(addr, &data, 1);                                                               
    printf("FoxBone output data 0x%4x on addr 0x%04x a total of %d times\n",data, addr, data2);
    break;                                                                                          
  case 'a':                                                                                         
    value = foxboneread(4);                                                                         
    printf("FoxBone release: 0x%04x\n", value);                                               
    value = foxboneread(5);                                                                         
    printf("FoxBone application word1: 0x%04x\n", value);                                     
    value = foxboneread(6);                                                                         
    printf("FoxBone application word2: 0x%04x\n", value);                                     
    value = foxboneread(7);                                                                         
    printf("FoxBone application word3: 0x%04x\n", value);                                     
    break;                                                                                          
  case 'p':                                                                                         
    bulk_data[0] = 0x13;                                                                            
    bulk_data[1] = 8;                                                                               
    bulk_data[2] = 1;                                                                               
    bulk_data[3] = 2;                                                                               
    bulk_data[4] = 1;                                                                               
    bulk_data[5] = 2;                                                                               
    bulk_data[6] = 1;                                                                               
    bulk_data[7] = 2;                                                                               
    bulk_data[8] = 1;                                                                               
    bulk_data[9] = 2;                                                                               
    foxbonebulkwrite(addr, &bulk_data, 10);                                                         
    break;                                                                                          
  case 'g':                                                                                         
    bulk_data[0] = 0x13;                                                                            
    bulk_data[1] = 10;                                                                              
    bulk_data[2] = 0;                                                                               
    bulk_data[3] = 0;                                                                               
    bulk_data[4] = 0;                                                                               
    bulk_data[5] = 0;                                                                               
    bulk_data[6] = 0;                                                                               
    bulk_data[7] = 0;                                                                               
    bulk_data[8] = 0;                                                                               
    bulk_data[9] = 0;                                                                               
    foxbonebulkread(addr, &bulk_data, 10);                                                          
    printf("%d\n", bulk_data[0]);
    printf("%d\n", bulk_data[1]);
    printf("%d\n", bulk_data[2]);   
    printf("%d\n", bulk_data[3]);   
    printf("%d\n", bulk_data[4]);   
    printf("%d\n", bulk_data[5]);   
    printf("%d\n", bulk_data[6]);   
    printf("%d\n", bulk_data[7]);   
    printf("%d\n", bulk_data[8]);   
    printf("%d\n", bulk_data[9]);   
    break;                          
  default:
    print_usage();
  }
}

int main(int argc, char **argv) {
  FoxBone_command(argc,argv); // launch the requested command
  return(0);
} // end main()


