#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>

#include "compile.h"

#define PAGE_ALIGN(addr)        (((addr) + ((4096)-1)) & (~((4096) - 1)))
#define SHM_DEV_NAME            ("/dev/shm_dev/shm0")

void mmap_test_read(void)
{
    unsigned int cnt = 0;
    unsigned char *pBuf;
    int fd = open(SHM_DEV_NAME, O_RDWR);

    if(fd == -1) {
        fprintf(stderr, "Open device %s error: %s\n", SHM_DEV_NAME, strerror(errno));
        return;
    }

    pBuf = (unsigned char *)mmap(NULL, PAGE_ALIGN(1024 * 1024), PROT_READ, MAP_SHARED | MAP_LOCKED, fd, 0);

    if(pBuf == NULL) {
        fprintf(stderr, "mmap memory %u error: %s\n", PAGE_ALIGN(1024 * 1024), strerror(errno));
        close(fd);
        return;
    }

    do {
        fprintf(stdout, "[%04u]: %s\n", cnt++, (char *)pBuf);
        sleep(1);
    } while(1);
}

void mmap_test_write(void)
{
    unsigned int cnt = 0;
    unsigned char *pBuf;
    int fd = open(SHM_DEV_NAME, O_RDWR);

    if(fd == -1) {
        fprintf(stderr, "Open device %s error: %s\n", SHM_DEV_NAME, strerror(errno));
        return;
    }

    pBuf = (unsigned char *)mmap(NULL, PAGE_ALIGN(1024 * 1024), PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);

    if(pBuf == NULL) {
        fprintf(stderr, "mmap memory %u error: %s\n", PAGE_ALIGN(1024 * 1024), strerror(errno));
        close(fd);
        return;
    }

    do {
        memset(pBuf, 0, 512);
        sprintf(pBuf, "Test %u times of share memory\n", cnt++);
        sleep(1);
    } while(1);
}

/**
 * @brief  应用程序主函数
 * @param  argc       输入参数个数
 * @param  argv       输入参数详细内容
 * @return 0
 */
int main(int argc, char **argv)
{
    int c, optidx = 0;
    static const struct option long_opts[] = {
        { "help", no_argument, NULL, 'h' },
        { "version", no_argument, NULL, 'v' },
        { "shm_read", no_argument, NULL, 'r' },
        { "shm_write", no_argument, NULL, 'w' },
        // TODO 添加其它需要处理的参数配置
        {NULL, 0, NULL, 0}
    };

    while((c = getopt_long(argc, argv, "hvrw", long_opts, &optidx)) != -1) {
        switch(c) {
            case 'v':
                fprintf(stdout, "User demo version: %s(%s)\n", sGATE_GIT_TAGS, sGATE_GIT_VERS);
                break;

            //TODO 添加其它必要处理参数过程
            case 'r':
                mmap_test_read();
                break;

            case 'w':
                mmap_test_write();
                break;

            case '?':
            case 'h':
                fprintf(stdout, "Usage: %s [-h] [-v] ...\n", argv[0]);
                fprintf(stdout, "options:\n");
                fprintf(stdout, "\t-v, --version show program version\n");
                fprintf(stdout, "\t-h, --help    print this message\n");
                break;
        }
    }

    return 0;
}