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

void *VirtualAlloc(void *lpAddress, unsigned long dwSize, unsigned long flAllocationType, unsigned long flProtect);
int VirtualCopy(void *lpvDest, void *lpvSrc, unsigned long cbSize, unsigned long fdwProtect);
int VirtualFree(void *lpAddress, unsigned long dwSize, unsigned long dwFreeType);

enum VirtualTypes {
	MEM_COMMIT = 0x1000,
	MEM_RESERVE = 0x2000,
	MEM_DECOMMIT = 0x4000,
	MEM_RELEASE = 0x8000,
};

enum VirtualProtection {
	PAGE_NOACCESS               = 0x01,
	PAGE_READONLY               = 0x02,
	PAGE_READWRITE              = 0x04,
	PAGE_EXECUTE                = 0x10,
	PAGE_EXECUTE_READ           = 0x20,
	PAGE_EXECUTE_READWRITE      = 0x40,
	PAGE_GUARD                  = 0x100,
	PAGE_NOCACHE                = 0x200,
	PAGE_PHYSICAL               = 0x400,
};


#define GPA_OFFSET	0x00
#define GPB_OFFSET	0x10
#define GPC_OFFSET	0x20
#define GPD_OFFSET	0x30
#define GPE_OFFSET	0x40
#define GPF_OFFSET	0x50
#define GPG_OFFSET	0x60
#define GPH_OFFSET	0x70

#define CONF		0x00
#define VALUE		0x04
#define PULLUP		0x08


/* Mask known bits */
#define GPA_MASK	~0x5E0001
#define GPB_MASK	~0x001
#define GPC_MASK	~0xF813
#define GPD_MASK	~0xF8FC
#define GPE_MASK	~0xC7FF
#define GPF_MASK	~0xC1
#define GPG_MASK	~0xF7DD
#define GPH_MASK	~0x0FD

void Sleep(long dwMilliseconds);

struct my_regs {
	char *name;
	unsigned long *addr;
	unsigned long value;
	unsigned long old_value;
	unsigned long mask;
	unsigned long offset;
} ;

int main(int argc, char **argv)
{
	struct my_regs regs[] = {
		[0] = {
			.name   = "GPA_CONF",
			.mask   = -1,
			.offset = GPA_OFFSET + CONF,
		},
		[1] = {
			.name = "GPB_CONF",
			.mask = -1,
			.offset = GPB_OFFSET + CONF,
		},
		[2] = {
			.name = "GPC_CONF",
			.mask = -1,
			.offset = GPC_OFFSET + CONF,
		},
		[3] = {
			.name = "GPD_CONF",
			.mask = -1,
			.offset = GPD_OFFSET + CONF,
		},
		[4] = {
			.name = "GPE_CONF",
			.mask = -1,
			.offset = GPE_OFFSET + CONF,
		},
		[5] = {
			.name = "GPF_CONF",
			.mask = -1,
			.offset = GPF_OFFSET + CONF,
		},
		[6] = {
			.name = "GPG_CONF",
			.mask = -1,
			.offset = GPG_OFFSET + CONF,
		},
		[7] = {
			.name = "GPH_CONF",
			.mask = -1,
			.offset = GPH_OFFSET + CONF,
		},
		[8] = {
			.name   = "GPA",
			.mask   = GPA_MASK,
			.offset = GPA_OFFSET + VALUE,
		},
		[9] = {
			.name = "GPB",
			.mask = GPB_MASK,
			.offset = GPB_OFFSET + VALUE,
		},
		[10] = {
			.name = "GPC",
			.mask = GPC_MASK,
			.offset = GPC_OFFSET + VALUE,
		},
		[11] = {
			.name = "GPD",
			.mask = GPD_MASK,
			.offset = GPD_OFFSET + VALUE,
		},
		[12] = {
			.name = "GPE",
			.mask = GPE_MASK,
			.offset = GPE_OFFSET + VALUE,
		},
		[13] = {
			.name = "GPF",
			.mask = GPF_MASK,
			.offset = GPF_OFFSET + VALUE,
		},
		[14] = {
			.name = "GPG",
			.mask = GPG_MASK,
			.offset = GPG_OFFSET + VALUE,
		},
		[15] = {
			.name = "GPH",
			.mask = GPH_MASK,
			.offset = GPH_OFFSET + VALUE,
		},
		[16] = {
			.name   = "GPA_PULL",
			.mask   = -1,
			.offset = GPA_OFFSET + PULLUP,
		},
		[17] = {
			.name = "GPB_PULL",
			.mask = -1,
			.offset = GPB_OFFSET + PULLUP,
		},
		[18] = {
			.name = "GPC_PULL",
			.mask = -1,
			.offset = GPC_OFFSET + PULLUP,
		},
		[19] = {
			.name = "GPD_PULL",
			.mask = -1,
			.offset = GPD_OFFSET + PULLUP,
		},
		[20] = {
			.name = "GPE_PULL",
			.mask = -1,
			.offset = GPE_OFFSET + PULLUP,
		},
		[21] = {
			.name = "GPF_PULL",
			.mask = -1,
			.offset = GPF_OFFSET + PULLUP,
		},
		[22] = {
			.name = "GPG_PULL",
			.mask = -1,
			.offset = GPG_OFFSET + PULLUP,
		},
		[23] = {
			.name = "GPH_PULL",
			.mask = -1,
			.offset = GPH_OFFSET + PULLUP,
		},

	};
	FILE *fp;
	unsigned long gpio_base=0x56000000;
	unsigned long size=0x10000;
	unsigned long change;
	unsigned long value;
	int cur_time = time (NULL);
	int fin_time = cur_time + 60;
	void *mem;
	int i;

	fp = fopen("My Documents\\toto.txt","a+");

	if (!fp)
		exit(1);

	/* Alloc memory and bind it */
	mem = VirtualAlloc (NULL,size,MEM_RESERVE, PAGE_NOACCESS);
	if (!mem) {
		fclose(fp);
		exit(1);
	}
    	
	if (!VirtualCopy(mem, (void *)(gpio_base >> 8),  size, PAGE_READWRITE | PAGE_PHYSICAL | PAGE_NOCACHE)) {
		VirtualFree(mem, 0, MEM_RELEASE);
		exit(1);
	}

	fprintf(fp,"Hello, World\r\n"); 
	for (i=0;i<sizeof(regs)/sizeof(regs[0]);i++) {
		regs[i].addr      = mem + regs[i].offset;
		regs[i].value     = *(regs[i].addr);
		fprintf(fp,"%s value at the beginning : %08lx\r\n", regs[i].name, regs[i].value);
		regs[i].value	 &= regs[i].mask;
	 	regs[i].old_value = regs[i].value;
	}


/*
 	asm ("  mrs     r2, cpsr ; \
		orr     r2, r2, #0xc0 ; \
		msr     cpsr_c, r2");
*/

	while ( cur_time <= fin_time) {
		for (i=0;i<sizeof(regs)/sizeof(regs[0]);i++) {
			regs[i].value     = *(regs[i].addr) & regs[i].mask;
			if (regs[i].value != regs[i].old_value) {
				change = regs[i].value ^ regs[i].old_value;
				value = regs[i].value & change;
				fprintf(fp,"%s changed : %08lx (%08lx)\r\n",\
						regs[i].name,change,value);
				regs[i].old_value = regs[i].value;
			}
		}
		cur_time = time (NULL);
	}

/*
	asm ("  mrs     r2, cpsr ; \
		and     r2, r2, #0x3f ; \
		msr     cpsr_c, r2");
*/
	for (i=0;i<sizeof(regs)/sizeof(regs[0]);i++) {
		fprintf(fp,"%s value at the end : %08lx\r\n", regs[i].name, *(regs[i].addr) & regs[i].mask);
	}
	
	/* Free Memory and close the file */
	VirtualFree(mem, 0, MEM_RELEASE);
	fclose(fp);

	
	return 0;
}
