Sunday, August 30, 2015

Flow Control and Print Format

I got tired of banging my head against the wall with the toolchain compiling. So I decided to just work on something else for a while.

This morning, I connected the CTS and RTS to the RS232 port. So, I'll start to see if I can do hardware flow control. Which I want since I have 1) a slow processor, 2) a limited 8 byte FIFO in the MAX3110E, and 3) a plan to run at the maximum baud rate. I still have to tie the IRQ to the CPU. Then I'll be done with communication connections.

I also am working on the parts of the C library that are missing while I'm not getting the toolchain to compile. Since the printf formatting has all kinds of stuff in it, I am just going to write my own minimal formatter. It won't do everything, but it will do everything I need. No floating point or  long long.

I also wrote some test code so I know that it works. At least well enough for now--with correct input.

// Formatter for printf, sprintf, vprintf, vsprintf, etc.
//  This is a very light and minimal formatter that includes only
//  a subset of the standard functionality. This list explains what
//  this light version is capable of:
//    %c - print character
//    %s - print string
//    %% - print '%'
//    %d - print signed int
//    %x - print unsigned int in hex
//    %p - print 2 byte unsigned pointer in hex
//    %#[xduls] - print and pad to # characters. If # starts with 0, use
//        leading zeros on unsigned int/long
//    %-#[sulds] - as above, but right justify
//    %l[xd] - 4 byte long instead of 2 byte int
//    %u[xd] - unsigned

void print_int(uint32_t data, int base, bool isUnsigned, bool leadingZeroes, int size, int length, bool rightJustify, char** pBuffer, void(*write)(char c, char** pBuffer))
{
    char buf[BUFLEN];
    static const char* ascii = "0123456789abcdef";
    int i = BUFLEN - 1;
    bool negSign = false;
    uint32_t udata = data;
    if (!isUnsigned && ((int32_t)data) < 0)
    {
        negSign = true;
        udata = (~data) + 1;
    }
    if (size == 2)
    {
        udata &= 0xffff;
    }
    do
    {
        buf[i--] = ascii[udata % base];
        udata = udata / base;
    } while (udata != 0);

    if (negSign)
    {
        buf[i--] = '-';
    }
    while (i >= 0 && length > (BUFLEN - i))
    {
        buf[i--] = leadingZeroes ? '0' : ' ';
    }
    i++; // move to the valid data
    for (; i < BUFLEN; i++)
    {
        write(buf[i], pBuffer);
    }
}

int print_format(void(*write)(char c, char** pBuffer), char** pBuffer, const char* format, va_list ap)
{
    char c;
    char* start = *pBuffer;
    int16_t len;
    bool isunsigned;
    int16_t base;
    bool leadingZero;
    bool neg;
    int16_t padding;
    long data;
    char* p;
    int i;

    // while not at end of line
    while (c = *format++)
    {
        if (c != '%')
        {
            write(c, pBuffer);
        }
        else
        {
            bool done = false;
            len = 2;
            isunsigned = false;
            leadingZero = false;
            neg = false;
            padding = 0;
            while (!done)
            {
                c = *format++;
                switch (c)
                {
                case '%':
                    write(c, pBuffer);
                    done = true;
                    break;
                case 's':
                    // get ptr from va_list
                    p = va_arg(ap, char*);
                    if (padding > 0)
                    {
                        int slen = strlen(p);
                        int spaces = padding - slen;
                        if (spaces > 0)
                        {
                            // padded string
                            if (neg)
                            {
                                for (i = 0; i < spaces; i++)
                                {
                                    write(' ', pBuffer);
                                }
                            }

                            while (c = *p)
                            {
                                write(c, pBuffer);
                            }

                            if (!neg)
                            {
                                for (i = 0; i < spaces; i++)
                                {
                                    write(' ', pBuffer);
                                }
                            }
                        }
                        else
                        {
                            // string longer than padding
                            while (c = *p)
                            {
                                write(c, pBuffer);
                            }
                        }
                    }
                    else
                    {
                        while (c = *p)
                        {
                            write(c, pBuffer);
                        }
                    }
                    done = true;
                    break;
                case 'c':
                    c = va_arg(ap, int); // char is promoted to int
                    write(c, pBuffer);
                    done = true;
                    break;
                case 'h':
                    len = 2;
                    break;
                case 'u':
                    isunsigned = true;
                    break;
                case 'l':
                    len = 4;
                    break;
                case '-':
                    neg = true;
                    break;
                case '0':
                    if (!padding)
                    {
                        // if no padding yet, then this means leading zeroes are shown
                        leadingZero = true;
                    }
                    // fall through
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    padding = padding * 10 + c - '0';
                    break;
                case 'p':
                    isunsigned = true;
                    len = 2;
                case 'd':
                case 'x':
                    base = c == 'd' ? 10 : 16; // 16 on x or p
                    if (len == 4)
                    {
                        data = va_arg(ap, long);
                    }
                    else
                    {
                        data = va_arg(ap, int);
                    }
                    print_int(data, base, isunsigned, leadingZero, len, padding, neg, pBuffer, write);
                    done = true;
                    break;
                }
            }
        }
    }
    **pBuffer = '\0';
    return *pBuffer - start;
}

No comments:

Post a Comment