
#include "printf.h"
#include "common.h"




//============================================================================
//函数名称：out_char
//功能概要：通过串口打出一个字符
//参数说明：uartNo:串口号：UART_0、UART_1、UART_2、UART_DEBUG
//       data:数据：通过串口发送的一字节数据
//函数返回：无
//============================================================================

void out_char(char data) {
    uart_send1(UART_Debug, data);
}
//============================================================================
//函数名称：printk_putc
//功能概要：通过串口打出一个字符
//参数说明：data:数据：通过串口发送的一字节数据
//函数返回：无
//============================================================================
static void printk_putc(int c, int *count, PRINTK_INFO *info)
{
    switch (info->dest) {
    case DEST_CONSOLE:
        info->func((char) c);
        break;
    case DEST_STRING:
        *(info->loc) = (unsigned char) c;
        ++(info->loc);
        break;
    default:
        break;
    }
    *count += 1;
}
//============================================================================
//函数名称：printk_mkfloatstr
//功能概要：将浮点数转化为字符串
//参数说明： *f:浮点型数据：float型数据
//       c[]:字符串数组：转化后的到的字符串数组
//函数返回：无
//============================================================================
int printk_mkfloatstr(double *f,char c[],int precision_width)
{
    uint_32 p,i,j,k,a[5]={0},b[19]={0};
    uint_64 q;
    double tempf;
    p=0;
    q=0;
    //float m;
    double m;
    p=(uint_32)*f;//整数部分
    tempf=(*f-p);
    if(precision_width==0)
    q=(*f-p)*100000000000000000;//小数部分
    else
    {
        while(precision_width--)
        tempf*=10;
        q=tempf;
    }
    m=*f-p;
    k=0;
    while(m<1)
    {
        m=m*10;
        k++;
    };
    k--;          //记录小数点后到第一位不为零的小数之前 有多少个0.

        i=0;
    if(0==p)//整数部分为0
        c[i++]='0';
    else//整数部分不为0
    {
        j=0;
        while(p!=0)//倒序的数字
        {
            a[j++]=p%10;
            p/=10;
        }
        while(j>0)//将倒序数字转为正序，并转换为对应的字符形式
        {
            c[i++]=a[j-1]+'0';
            --j;
        }
    }
    c[i++]='.';//小数点
    if(0==q)//小数部分为0
        c[i++]='0';
    else//小数部分不为0
    {
        j=0;

        while(q!=0)//倒序的数字
        {
            b[j++]=q%10;
            q/=10;
        }
        while(k!=0)
        {
            b[j++]=0;
            k--;
        }
        while(j>0)//将倒序数字转为正序，并转换为对应的字符形式
        {
            c[i++]=b[j-1]+'0';
            --j;
        }
    }
    c[i]='\0';
    return i;
}
//============================================================================
//函数名称：printk_mknumstr
//功能概要：将整形数据转化为字符串保存在numstr中
//参数说明：numstr:字符串首地址：用于接收转化为字符串的整型数据
//       nump:无符号整形数据：将转化为整形的数据传入函数
//       neg:有无符号:判断数据时有符号还是无符号整形
//       radix:格式选择:确定输出格式例如：十进制或十六进制...
//函数返回：无
//============================================================================
static int printk_mknumstr(char *numstr, void *nump, int neg, int radix)
{
    int a, b, c;
    unsigned int ua, ub, uc;

    int nlen;
    char *nstrp;

    nlen = 0;
    nstrp = numstr;
    *nstrp++ = '\0';

    if (neg) {
        a = *(int *) nump;
        if (a == 0) {
            *nstrp = '0';
            ++nlen;
            goto done;
        }
        while (a != 0) {
            b = (int) a / (int) radix;
            c = (int) a - ((int) b * (int) radix);
            if (c < 0) {
                c = ~c + 1 + '0';
            } else {
                c = c + '0';
            }
            a = b;
            *nstrp++ = (char) c;
            ++nlen;
        }
    } else {
        ua = *(unsigned int *) nump;
        if (ua == 0) {
            *nstrp = '0';
            ++nlen;
            goto done;
        }
        while (ua != 0) {
            ub = (unsigned int) ua / (unsigned int) radix;
            uc = (unsigned int) ua - ((unsigned int) ub * (unsigned int) radix);
            if (uc < 10) {
                uc = uc + '0';
            } else {
                uc = uc - 10 + 'A';
            }
            ua = ub;
            *nstrp++ = (char) uc;
            ++nlen;
        }
    }
    done: return nlen;
}
/********************************************************************/
static void printk_pad_zero(int curlen, int field_width, int *count,
        PRINTK_INFO *info) {
    int i;

    for (i = curlen; i < field_width; i++) {
        printk_putc('0', count, info);
    }
}

/********************************************************************/
static void printk_pad_space(int curlen, int field_width, int *count,
        PRINTK_INFO *info) {
    int i;

    for (i = curlen; i < field_width; i++) {
        printk_putc(' ', count, info);
    }
}
//============================================================================
//函数名称：printk
//功能概要：根据接收的参数信息对数据进行打印输出
//参数说明：info:传递字符串的信息
//       fmt:输出格式信息
//       ap:va_list指针指向格式信息输出
//函数返回：无
//============================================================================
int printk(PRINTK_INFO *info, const char *fmt, va_list ap)
{
    union ftooc
    {
        double a1;
        struct{
            int c1;
            int c2;
        };
        struct{
            char b1;
            char b2;
            char b3;
            char b4;
            char b5;
            char b6;
            char b7;
            char b8;
        }tempc;

    }un1;
    char *p;
    int c;
    char temp1;
    char vstr[33]={'0'};
    char *vstrp;
    int vlen;

    int done;
    int count;

    int flags_used;
    int field_width;
    int length_modifier;
    int precision_used;
    int precision_width;

    int ival;                  //用来接收整形数据
    double fval;                //用来接收浮点数据
    int schar, dschar;
    int *ivalp;
    char *sval;
    int cval;
    unsigned int uval;

    count = 0;
    length_modifier=0;
    precision_used=TRUE;
    //从格式字符串第一个字符开始格式化输出数据
    for (p = (char *) fmt; (c = *p) != 0; p++)
    {
        //读取%前面的字符，直接输出的字符和最后的\n类的转义字符
        if (c != '%')
        {
#ifndef UNIX_DEBUG
            //%之前的字符
            if (c != '\n') {
                printk_putc(c, &count, info);
            }
            //输出换行符
            else {
                printk_putc(0x0D /* CR */, &count, info);
                printk_putc(0x0A /* LF */, &count, info);
            }
#else
            printk_putc(c, &count, info);
#endif

            continue;
        }


        //此时字符为%  查看百分号后的第一个格式字符，对输出格式字符并做出相应输出判断
        //检查相应的修改标志
        flags_used = 0;
        done = FALSE;
        while (!done) {
            switch (/* c = */*++p) {
            case '-':
                flags_used |= FLAGS_MINUS;
                break;
            case '+':
                flags_used |= FLAGS_PLUS;
                break;
            case ' ':
                flags_used |= FLAGS_SPACE;
                break;
            case '0':
                flags_used |= FLAGS_ZERO;
                break;
            case '#':
                flags_used |= FLAGS_POUND;
                break;
            default:
                /* we've gone one char too far */
                --p;
                done = TRUE;
                break;
            }
        }


        //检查%后再下一个字符 确定输出长度
        field_width = 0;
        done = FALSE;
        while (!done) {
            switch (c = *++p) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                field_width = (field_width * 10) + (c - '0');
                break;
            default:
                /* we've gone one char too far */
                --p;
                done = TRUE;
                break;
            }
        }
        //此时字符为%看是否有.输入
        if (/* (c = *++p) */*++p == '.') {
            /* precision_used = TRUE; */

            /*
             * Must get precision field width, if present.
             */
            precision_width = 0;
            done = FALSE;
            while (!done) {
                switch ( c = *++p) {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
#if 1
                precision_width = (precision_width * 10) +    (c - '0');

#endif
                    break;
                default:
                    /* we've gone one char too far */
                    --p;
                    done = TRUE;
                    break;
                }
            }
        } else {
            /* we've gone one char too far */
            --p;
#if 1
            precision_used = FALSE;
            precision_width = 0;
#endif
        }
        //判断 输出的是否有lf、LF等
        switch (/* c = */*++p) {
        case 'h':
            // length_modifier |= LENMOD_h;
            break;
        case 'l':
             length_modifier |= LENMOD_l;
            break;
        case 'L':
             length_modifier |= LENMOD_L;
            break;
        default:
            /* we've gone one char too far */
            --p;
            break;
        }

        //p为格式字符串的首地址
        switch (c = *++p) {
        case 'd':
        case 'i':
             //此时ap为指向可变参数列表的第一个参数
            ival = (int) va_arg(ap, int);  //返回当前参数，并将ap指向下一个参数
            vlen = printk_mknumstr(vstr, &ival, TRUE, 10);//将整型转换成字符型保存在vstr中，返回字符数vlen
            vstrp = &vstr[vlen];  //指向转换后的最后一个字符

            //若参数小于0，添加'-'号，并将字符长度加1
            if (ival < 0) {
                schar = '-';
                ++vlen;
            }
            //若参数不小于0，添加‘+’号或者‘ ’或者为0，并将字符长度加1
            else {
                if (IS_FLAG_PLUS(flags_used)) {
                    schar = '+';
                    ++vlen;
                } else {
                    if (IS_FLAG_SPACE(flags_used)) {
                        schar = ' ';
                        ++vlen;
                    } else {
                        schar = 0;
                    }
                }
            }
            dschar = FALSE;

            /*
             * do the ZERO pad.
             */
            if (IS_FLAG_ZERO(flags_used)) {
                if (schar)
                    printk_putc(schar, &count, info);  //输出符号
                dschar = TRUE;
                printk_pad_zero(vlen, field_width, &count, info);
                vlen = field_width;
            } else {
                if (!IS_FLAG_MINUS(flags_used)) {
                    printk_pad_space(vlen, field_width, &count, info);  //输出空格

                    if (schar)
                        printk_putc(schar, &count, info);
                    dschar = TRUE;
                }
            }

            /* the string was built in reverse order, now display in */
            /* correct order */
            if (!dschar && schar) {
                printk_putc(schar, &count, info);
            }
            goto cont_xd;  //开始跳转

        //------------------此处添加浮点数输出功能---------------------------------------
        case 'f':
            //浮点型数据被当做 double型处理，组合方式如下：
            //3.140001 对应浮点数:0x0x4048F5C3；
            //3.140001 对double数:0x40091EB85F577E6C
            //实际传入变参数 函数后 浮点数变为:0x6000000040091EB8 实际是将其转化为double型数据
            //但是顺序反了，我们要做的是将后四字节提前，然后把0x60移到紧接着前四个字节后的位置。
            if(length_modifier==0)
            {
            un1.a1 = (double ) va_arg(ap, double);  //返回当前参数，并将ap指向下一个参数
            temp1=un1.tempc.b8;
            un1.c2=un1.c1;
            un1.c1=un1.c1&0x0000;
            un1.tempc.b4=temp1;
            fval=un1.a1;
            }
            else if(length_modifier==1 || length_modifier==2)
            {
                ap=ap+4;
                fval= (double)va_arg(ap,double);
            }
            //确定是否使用小数点精度数值
            if(precision_used)
            {
                vlen = printk_mkfloatstr(&fval,vstr,precision_width);//将整型转换成字符型保存在vstr中，返回字符数vlen
                vstrp = &vstr[0];  //指向转换后的第一个字符
            }
            else
            {
                if(length_modifier==0)   //浮点型精度到小数点后8位
                {
                    vlen = printk_mkfloatstr(&fval,vstr,8);//将整型转换成字符型保存在vstr中，返回字符数vlen
                    vstrp = &vstr[0];  //指向转换后的第一个字符
                }
                else
                {
                    vlen = printk_mkfloatstr(&fval,vstr,precision_width);//将整型转换成字符型保存在vstr中，返回字符数vlen
                    vstrp = &vstr[0];  //指向转换后的第一个字符
                }

            }

            //若参数小于0，添加'-'号，并将字符长度加1
            if (fval < 0) {
                schar = '-';
                ++vlen;
            }
            //若参数不小于0，添加‘+’号或者‘ ’或者为0，并将字符长度加1
            else {
                if (IS_FLAG_PLUS(flags_used)) {
                    schar = '+';
                    ++vlen;
                } else {
                    if (IS_FLAG_SPACE(flags_used)) {
                        schar = ' ';
                        ++vlen;
                    } else {
                        schar = 0;
                    }
                }
            }
            dschar = FALSE;

            /*
             * do the ZERO pad.
             */
            if (IS_FLAG_ZERO(flags_used)) {
                if (schar)
                    printk_putc(schar, &count, info);  //输出符号
                dschar = TRUE;
                printk_pad_zero(vlen, field_width, &count, info);
                vlen = field_width;
            } else {
                if (!IS_FLAG_MINUS(flags_used)) {
                    printk_pad_space(vlen, field_width, &count, info);  //输出空格

                    if (schar)
                        printk_putc(schar, &count, info);
                    dschar = TRUE;
                }
            }

            /* the string was built in reverse order, now display in */
            /* correct order */
            if (!dschar && schar) {
                printk_putc(schar, &count, info);
            }
            while (*vstrp)
                printk_putc(*vstrp++, &count, info);
            if (IS_FLAG_MINUS(flags_used)) {
                printk_pad_space(vlen, field_width, &count, info);
            }
            break;
        //以下是16进制整形输出
        case 'x':
        case 'X':
            uval = (unsigned int) va_arg(ap, unsigned int);
            vlen = printk_mknumstr(vstr, &uval, FALSE, 16);
            vstrp = &vstr[vlen];

            dschar = FALSE;
            if (IS_FLAG_ZERO(flags_used)) {
                if (IS_FLAG_POUND(flags_used)) {
                    printk_putc('0', &count, info);
                    printk_putc('x', &count, info);
                    /*vlen += 2;*/
                    dschar = TRUE;
                }
                printk_pad_zero(vlen, field_width, &count, info);
                vlen = field_width;
            } else {
                if (!IS_FLAG_MINUS(flags_used)) {
                    if (IS_FLAG_POUND(flags_used)) {
                        vlen += 2;
                    }
                    printk_pad_space(vlen, field_width, &count, info);
                    if (IS_FLAG_POUND(flags_used)) {
                        printk_putc('0', &count, info);
                        printk_putc('x', &count, info);
                        dschar = TRUE;
                    }
                }
            }

            if ((IS_FLAG_POUND(flags_used)) && !dschar) {
                printk_putc('0', &count, info);
                printk_putc('x', &count, info);
                vlen += 2;
            }
            goto cont_xd;
        //无符号以八进制表示的整数输出
        case 'o':
            uval = (unsigned int) va_arg(ap, unsigned int);
            vlen = printk_mknumstr(vstr, &uval, FALSE, 8);
            goto cont_u;
        //二进制输出
        case 'b':
            uval = (unsigned int) va_arg(ap, unsigned int);
            vlen = printk_mknumstr(vstr, &uval, FALSE, 2);
            goto cont_u;
        //输出指针的值
        case 'p':
            uval = (unsigned int) va_arg(ap, void *);
            vlen = printk_mknumstr(vstr, &uval, FALSE, 16);
            goto cont_u;
        case 'u':
            uval = (unsigned int) va_arg(ap, unsigned int);
            vlen = printk_mknumstr(vstr, &uval, FALSE, 10);

            cont_u: vstrp = &vstr[vlen];

            if (IS_FLAG_ZERO(flags_used)) {
                printk_pad_zero(vlen, field_width, &count, info);
                vlen = field_width;
            } else {
                if (!IS_FLAG_MINUS(flags_used)) {
                    printk_pad_space(vlen, field_width, &count, info);
                }
            }

            cont_xd: while (*vstrp)
                printk_putc(*vstrp--, &count, info);

            if (IS_FLAG_MINUS(flags_used)) {
                printk_pad_space(vlen, field_width, &count, info);
            }

            break;
        //字符型输出
        case 'c':
            cval = (char) va_arg(ap, unsigned int);
            printk_putc(cval, &count, info);
            break;
        case 's':
            sval = (char *) va_arg(ap, char *);
            if (sval) {
                vlen = strlen(sval);
                if (!IS_FLAG_MINUS(flags_used)) {
                    printk_pad_space(vlen, field_width, &count, info);
                }
                if(precision_width!=0)
                {
                    while (*sval)
                    {
                        if(precision_width)
                        {
                            precision_width--;
                            printk_putc(*sval++, &count, info);
                        }
                        else
                        *sval++;
                    }
                }
                else
                {
                    while (*sval)
                       printk_putc(*sval++, &count, info);
                }
                if (IS_FLAG_MINUS(flags_used)) {
                    printk_pad_space(vlen, field_width, &count, info);
                }
            }
            break;
        case 'n':
            ivalp = (int *) va_arg(ap, int *);
            *ivalp = count;
            break;

        default:
            printk_putc(c, &count, info);
            break;
        }
    }
    return count;
}
//============================================================================
//函数名称：myprintf
//功能概要：根据输入的参数进行解析然后将数据通过串口打出
//参数说明：const char *:打印参数字符串：对输入的字符串进行解析并按格式输出
//       例如： printf("c=%c\n",c); 将c按char型进行输出
//函数返回：字符串长度
//============================================================================
int myprintf(const char *fmt, ...)
{
    va_list ap;
    int rvalue;
    PRINTK_INFO info;
    info.dest = DEST_CONSOLE;  //宏定义为1
    info.func = &out_char;     //调用的串口输出函数
    va_start(ap, fmt);  //对ap 进行初始化，让它指向可变参数表里面的第一个参数
    rvalue = printk(&info, fmt, ap);

    va_end(ap);

    return rvalue;
}

