/* 
 * File:   main.c
 * Author: janesconference
 *
 * Created on September 13, 2011, 11:09 AM
 */

#include <stdio.h>
#include <stdlib.h>
#include <stropts.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>


#define ACQ_DEV "/dev/mmap_test"
#define HEADER_SIZE 32
/* The file descriptor for the device */
static int fd;
int i, retval;
char* buffer;

int main(int argc, char** argv) {
    

    int shared = 0;
    int private = 0;
    int anonymous = 0;
    int fixed = 0;
    int invalidate = 0;
    
    int c;

    opterr = 0;

    while ((c = getopt (argc, argv, "spafui")) != -1)
    switch (c)
      {
      case 's':
        shared = 1;
        break;
      case 'p':
        private = 1;
        break;
      case 'a':
        anonymous = 1;
        break;
      case 'f':
        fixed = 1;
        break;
        case 'i':
        invalidate = 1;
        break;
      case '?':
        if (isprint (optopt))
          fprintf (stderr, "Unknown option `-%c'.\n", optopt);
        else
          fprintf (stderr,
                   "Unknown option character `\\x%x'.\n",
                   optopt);
        return 1;
      default:
        abort ();
      }

    int flags;
    
    if (shared && private) {
        printf ("can't map private AND shared. Setting to default (private)\n");
        shared = 0;
        flags = MAP_PRIVATE;
    }
    
    if (!shared && !private) {
        shared = 0;
        printf ("can't map not shared nor private. Setting to default (private)\n");
        flags = MAP_PRIVATE;
    }
    
    if (shared) {
        printf ("setting MAP_SHARED\n");
        flags = MAP_SHARED;
    }
    
    if (private) {
        printf ("setting MAP_PRIVATE\n");
        flags = MAP_PRIVATE;
    }
    
    if (anonymous) {
        printf ("setting MAP_ANONYMOUS\n");
        flags |= MAP_ANONYMOUS;
    }
    
    if (fixed) {
        printf ("setting MAP_FIXED\n");
        flags |= MAP_FIXED;
    }
    
    int real_frame_len = 4096;
    
    printf ("Opening file descriptor %s\n", ACQ_DEV);
    /* Open the device file descriptor*/
    fd = open(ACQ_DEV,O_RDONLY);
    if ( fd < 0 ) {
        fprintf (stderr, "%s\n", strerror(errno));
        return -1;
    }
    printf ("Opened file descriptor %s\n", ACQ_DEV);
    
    printf ("mmapping mmap buffer number %d with size: %lu \n", i, real_frame_len);
        buffer = mmap(NULL, real_frame_len, PROT_READ | PROT_WRITE, flags, fd, 0);
        if (buffer == MAP_FAILED){
            perror("mmap failed");
            fprintf (stderr, "mmap size: %d offset: 0\n", real_frame_len);
            return -1;
        }
        
    printf("Base userspace address for mmapped buffer is %p\n",buffer);
    
    flags = MS_SYNC;
    
    if (invalidate) {
        printf ("setting MS_INVALIDATE\n");
        flags |= MS_INVALIDATE;
    }
        
    for (i = 0; i < 4096; i+=1) {

        char character = i % 0xFF;
        buffer[i] = character;
        printf("Wrote %02X in user-space %p. Reading from it seems %02X\n", character, buffer + i, buffer[i]);
        retval = msync(buffer, 4096, flags);
        if (retval == -1) {
            perror ("error syncyng mmap\n");
        }
        getchar();
        
    }
    
    return (EXIT_SUCCESS);
}
