Rtthread kservice中的系列函数
/* global errno in RT-Thread */
static volatile int __rt_errno;
/*
* This function will get errno
*
* @return errno
*/
//errno获取函数
rt_err_t rt_get_errno(void)
{
rt_thread_t tid;
if (rt_interrupt_get_nest() != 0)
{
/* it's in interrupt context */
return __rt_errno;
}
tid = rt_thread_self();
if (tid == RT_NULL)
return __rt_errno;
return tid->error;
}
/*
* This function will set errno
*
* @param error the errno shall be set
*/
void rt_set_errno(rt_err_t error)
{
rt_thread_t tid;
if (rt_interrupt_get_nest() != 0)
{
/* it's in interrupt context */
__rt_errno = error;
return;
}
tid = rt_thread_self();
if (tid == RT_NULL)
{
__rt_errno = error;
return;
}
tid->error = error;
}
/**
* This function returns errno.
*
* @return the errno in the system
*/
int *_rt_errno(void)
{
rt_thread_t tid;
if (rt_interrupt_get_nest() != 0)
return (int *)&__rt_errno;
tid = rt_thread_self();
if (tid != RT_NULL)
return (int *) & (tid->error);
return (int *)&__rt_errno;
}
/**
* This function will set the content of memory to specified value
*
* @param s the address of source memory
* @param c the value shall be set in content
* @param count the copied length
*
* @return the address of source memory
*/
void *rt_memset(void *s, int c, rt_ubase_t count)
{
#define LBLOCKSIZE (sizeof(long)) //32BIT 平台long为4字节
#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) //没有4字节对齐为true
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)//小于4字节
unsigned int i;
char *m = (char *)s;
unsigned long buffer;
unsigned long *aligned_addr;
unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an
unsigned variable. */
if (!TOO_SMALL(count) && !UNALIGNED(s))// count >= 4 && 4align
{
/* If we get this far, we know that n is large and m is word-aligned. */
aligned_addr = (unsigned long *)s;
/* Store D into each char sized location in BUFFER so that
* we can set large blocks quickly.
*/
if (LBLOCKSIZE == 4)
{//buffer == [d][d][d][d]
buffer = (d << 8) | d;
buffer |= (buffer << 16);
}
else //sizeof long != 4
{
buffer = 0;
for (i = 0; i < LBLOCKSIZE; i ++)
buffer = (buffer << 8) | d;
}
while (count >= LBLOCKSIZE * 4)
{//一次给 4字节地址赋值,效率最高
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
*aligned_addr++ = buffer;
count -= 4 * LBLOCKSIZE;
}
while (count >= LBLOCKSIZE)//不足4*LBLOCKSIZE 但是 >= LBLOCKSIZE
{
*aligned_addr++ = buffer;
count -= LBLOCKSIZE;
}
/* Pick up the remainder with a bytewise loop. */
m = (char *)aligned_addr;// m
}
while (count--) //剩下不满LBLOCKSIZE的字节赋值
{
*m++ = (char)d;
}
return s;
#undef LBLOCKSIZE
#undef UNALIGNED
#undef TOO_SMALL
}
/**
* This function will copy memory content from source address to destination
* address.
*
* @param dst the address of destination memory
* @param src the address of source memory
* @param count the copied length
*
* @return the address of destination memory
*/
void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
{
#define UNALIGNED(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
#define BIGBLOCKSIZE (sizeof (long) << 2) //4 << 2 == 16
#define LITTLEBLOCKSIZE (sizeof (long)) // 4
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) // LEN < 16
char *dst_ptr = (char *)dst;
char *src_ptr = (char *)src;
long *aligned_dst;
long *aligned_src;
int len = count;
/* If the size is small, or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr))//len >= 16 && src_ptr, dst_ptr都是4align
{
aligned_dst = (long *)dst_ptr;
aligned_src = (long *)src_ptr;
/* Copy 4X long words at a time if possible. */
while (len >= BIGBLOCKSIZE)//len >= 16
{
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
*aligned_dst++ = *aligned_src++;
len -= BIGBLOCKSIZE;
}
/* Copy one long word at a time if possible. */
while (len >= LITTLEBLOCKSIZE) // len >= 4
{
*aligned_dst++ = *aligned_src++;
len -= LITTLEBLOCKSIZE;
}
/* Pick up any residual with a byte copier. */
dst_ptr = (char *)aligned_dst;//剩下未被操作的地址
src_ptr = (char *)aligned_src;
}
while (len--)
*dst_ptr++ = *src_ptr++;
return dst;
#undef UNALIGNED
#undef BIGBLOCKSIZE
#undef LITTLEBLOCKSIZE
#undef TOO_SMALL
}
/**
* This function will move memory content from source address to destination
* address.
*
* @param dest the address of destination memory
* @param src the address of source memory
* @param n the copied length
*
* @return the address of destination memory
*/
void *rt_memmove(void *dest, const void *src, rt_ubase_t n)
{
char *tmp = (char *)dest, *s = (char *)src;
// s<tmp 并且 s与tmp指向的内存空间重叠
if (s < tmp && tmp < s + n)
{
tmp += n;
s += n;
//从地址尾部拷贝
while (n--)
*(--tmp) = *(--s);
}
else
{
//s < tmp 并且两块内存空间不重叠,或者s > tmp
while (n--)
*tmp++ = *s++;
}
return dest;
}
/**
* This function will compare two areas of memory
*
* @param cs one area of memory
* @param ct another area of memory
* @param count the size of the area
*
* @return the result
*/
rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count)
{
const unsigned char *su1, *su2;
int res = 0;
//遍历每一个字节,对比其大小
for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
/**
* This function will return the first occurrence of a string.
*
* @param s1 the source string
* @param s2 the find string
*
* @return the first occurrence of a s2 in s1, or RT_NULL if no found.
*/
char *rt_strstr(const char *s1, const char *s2)
{
int l1, l2;
l2 = rt_strlen(s2);
if (!l2)
return (char *)s1;
l1 = rt_strlen(s1);
//l1 > l2时
while (l1 >= l2)
{
l1 --;
if (!rt_memcmp(s1, s2, l2))//从s1中查找子字符串s2首地址,找到rt_memcmp返回0
return (char *)s1;
s1 ++;
}
return RT_NULL;
}
/**
* This function will compare two strings while ignoring differences in case
*
* @param a the string to be compared
* @param b the string to be compared
*
* @return the result
*/
//忽略大小写比较字符串
rt_int32_t rt_strcasecmp(const char *a, const char *b)
{
int ca, cb;
do
{
ca = *a++ & 0xff;
cb = *b++ & 0xff;
if (ca >= 'A' && ca <= 'Z')
ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z')
cb += 'a' - 'A';
}
while (ca == cb && ca != '\0');
return ca - cb;
}
/**
* This function will copy string no more than n bytes.
*
* @param dst the string to copy
* @param src the string to be copied
* @param n the maximum copied length
*
* @return the result
*/
char *rt_strncpy(char *dst, const char *src, rt_ubase_t n)
{
if (n != 0)
{
char *d = dst;
const char *s = src;
do
{
if ((*d++ = *s++) == 0)//已经拷贝到src的尾部
{
/* NUL pad the remaining n-1 bytes */
while (--n != 0) //剩下的空间全部置0
*d++ = 0;
break;
}
} while (--n != 0);
}
return (dst);
}
/**
* This function will compare two strings with specified maximum length
*
* @param cs the string to be compared
* @param ct the string to be compared
* @param count the maximum compare length
*
* @return the result
*/
rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count)
{
register signed char __res = 0;
while (count)
{
if ((__res = *cs - *ct++) != 0 || !*cs++)//字符不相等或者*cs 为0 退出
break;
count --;
}
return __res;
}
/**
* This function will compare two strings without specified length
*
* @param cs the string to be compared
* @param ct the string to be compared
*
* @return the result
*/
rt_int32_t rt_strcmp(const char *cs, const char *ct)
{
while (*cs && *cs == *ct)// *cs != '\0' and *cs == *ct
{
cs++;
ct++;
}
return (*cs - *ct); // 非0则两个字符串不相等
}
/**
* The strnlen() function returns the number of characters in the
* string pointed to by s, excluding the terminating null byte ('\0'),
* but at most maxlen. In doing this, strnlen() looks only at the
* first maxlen characters in the string pointed to by s and never
* beyond s+maxlen.
*
* @param s the string
* @param maxlen the max size
* @return the length of string
*/
rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
{
const char *sc;
for (sc = s; *sc != '\0' && (rt_ubase_t)(sc - s) < maxlen; ++sc) /* nothing */
;
return sc - s;
}
/**
* This function will return the length of a string, which terminate will
* null character.
*
* @param s the string
*
* @return the length of string
*/
rt_size_t rt_strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc) /* nothing */
;
return sc - s;
}
#ifdef RT_USING_HEAP
/**
* This function will duplicate a string.
*
* @param s the string to be duplicated
*
* @return the duplicated string pointer
*/
//将s 的内容复制到新的一块申请的内存中
char *rt_strdup(const char *s)
{
rt_size_t len = rt_strlen(s) + 1;
char *tmp = (char *)rt_malloc(len);
if (!tmp)
return RT_NULL;
rt_memcpy(tmp, s, len);
return tmp;
}
rt_inline int divide(long *n, int base)
{
int res;
/* optimized for processor which does not support divide instructions. */
if (base == 10)
{
res = (int)(((unsigned long)*n) % 10U);
*n = (long)(((unsigned long)*n) / 10U);
}
else
{
res = (int)(((unsigned long)*n) % 16U);
*n = (long)(((unsigned long)*n) / 16U);
}
return res;
}
rt_inline int skip_atoi(const char **s)
{
register int i = 0;
while (_ISDIGIT(**s))
i = i * 10 + *((*s)++) - '0';
return i;
}
static char *print_number(char *buf,
char *end,
long num,
int base,
int s,
int precision,
int type)
{
char c, sign;
#ifdef RT_PRINTF_LONGLONG
char tmp[32];
#else
char tmp[16];
#endif
int precision_bak = precision;//记录精度
const char *digits;
static const char small_digits[] = "0123456789abcdef";
static const char large_digits[] = "0123456789ABCDEF";
register int i;
register int size;
size = s; //输出长度
digits = (type & LARGE) ? large_digits : small_digits;//大小写由字符0x/0X决定
if (type & LEFT) //LEFT type 将ZEROPAD清零
type &= ~ZEROPAD;
c = (type & ZEROPAD) ? '0' : ' ';//ZEROPAD 用来将空格补0
/* get sign */
sign = 0;
if (type & SIGN) //有符号
{
if (num < 0)//显示符号
{
sign = '-';
num = -num;
}
else if (type & PLUS)//字符串中的+号
sign = '+';
else if (type & SPACE)//空格
sign = ' ';
}
#ifdef RT_PRINTF_SPECIAL
if (type & SPECIAL) //特殊字符#
{
if (base == 16)//添加0x
size -= 2;
else if (base == 8)//添加O
size--;
}
#endif
i = 0;
if (num == 0)//形参num的值==0
tmp[i++] = '0';
else //形参num的值!=0
{
while (num != 0)
tmp[i++] = digits[divide(&num, base)];//将long类型的数据分别转换成base指定的字符,顺序反的
}
#ifdef RT_PRINTF_PRECISION
if (i > precision) //i此时是该Num转换成char后的长度
precision = i;
size -= precision;//size为空格的长度
#else
size -= i;
#endif
//type 既不是左对齐也不需要补0
if (!(type & (ZEROPAD | LEFT)))
{
if ((sign) && (size > 0))
size--;
while (size-- > 0)//左边补空格
{
if (buf < end)
*buf = ' ';
++ buf;
}
}
if (sign)//有符号
{
if (buf < end)
{
*buf = sign;//显示符号
}
-- size;//符号占用一个字节
++ buf;
}
#ifdef RT_PRINTF_SPECIAL
if (type & SPECIAL)//#号
{
if (base == 8)//8进制
{
if (buf < end)
*buf = '0';//0开头
++ buf;
}
else if (base == 16)
{
if (buf < end)
*buf = '0';
++ buf;
if (buf < end)
{
*buf = type & LARGE ? 'X' : 'x';//0x还是0X
}
++ buf;
}
}
#endif
/* no align to the left */
if (!(type & LEFT))//非左对齐,但是ZEROPAD标志为true,左边补字符c('0')
{
while (size-- > 0)
{
if (buf < end)
*buf = c;
++ buf;
}
}
#ifdef RT_PRINTF_PRECISION
while (i < precision--)//输出精度不够,补0
{
if (buf < end)
*buf = '0';
++ buf;
}
#endif
/* put number in the temporary buffer */
while (i-- > 0 && (precision_bak != 0))//将tmp中的字符填到buf中
{
if (buf < end)
*buf = tmp[i];
++ buf;
}
while (size-- > 0)//左对齐的情况,剩下长度填空格
{
if (buf < end)
*buf = ' ';
++ buf;
}
return buf;
}
rt_int32_t rt_vsnprintf(char *buf,
rt_size_t size,
const char *fmt,
va_list args)
{
rt_uint32_t num;
int i, len;
char *str, *end, c;
const char *s;
rt_uint8_t base; /* the base of number */
rt_uint8_t flags; /* flags to print number */
rt_uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */
rt_int32_t field_width; /* width of output field */
#ifdef RT_PRINTF_PRECISION
int precision; /* min. # of digits for integers and max for a string */
#endif
str = buf;
end = buf + size;
/* Make sure end is always >= buf */
if (end < buf)
{
end = ((char *) - 1);
size = end - buf;
}
for (; *fmt ; ++fmt) //遍历字串参数
{
if (*fmt != '%')//取出非格式化字符放到str中
{
if (str < end)
*str = *fmt;
++ str;
continue;
}
/* process flags */
flags = 0;
//[标志][输出最少宽度][.精度][长度]类型
while (1) //获取标志
{
/* skips the first '%' also */
++ fmt;
if (*fmt == '-') flags |= LEFT; //左对齐
else if (*fmt == '+') flags |= PLUS; //右对齐
else if (*fmt == ' ') flags |= SPACE; //空格:若符号为正,则显示空格,负则显示"-"
else if (*fmt == '#') flags |= SPECIAL;//对o类输出时加前缀o;对x类输出时加前缀0x;
else if (*fmt == '0') flags |= ZEROPAD;//0:有0表示指定空位填0,如省略表示指定空位不填
else break;
}
/* get field width */
field_width = -1; //输出格式总长度
// *fmt是数字则取出数字长度,并且fmt += field_width
//printf("%*.*s\n",m,n,ch);前边的*定义的是总的宽度,后边的定义的是输出的个数。
//分别对应外面的参数m和n
if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt);
else if (*fmt == '*')//否则*fmt == *
{
++ fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0)//形参指定的输出宽度小于0的话,则表示左对齐
{
field_width = -field_width;
flags |= LEFT;
}
}
#ifdef RT_PRINTF_PRECISION
/* get the precision */
precision = -1;
if (*fmt == '.')
{
++ fmt;
if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt);//输出的个数(n)
else if (*fmt == '*')
{
++ fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0) precision = 0;//不能小于0
}
#endif
/* get the conversion qualifier */
qualifier = 0;
//l h要搭配d/u等使用
if (*fmt == 'h' || *fmt == 'l')//l对应为long, h对应位short
{
qualifier = *fmt;
++ fmt;
#ifdef RT_PRINTF_LONGLONG
if (qualifier == 'l' && *fmt == 'l')
{
qualifier = 'L';
++ fmt;
}
#endif
}
/* the default base */
base = 10;//默认十进制
switch (*fmt)//判断控制符
{
case 'c'://字符
if (!(flags & LEFT))//非左对齐
{
while (--field_width > 0)//前面先输出空格,最后一个位置给字符
{
if (str < end) *str = ' ';
++ str;
}
}
/* get character */
c = (rt_uint8_t)va_arg(args, int);//获取字符对应的实参的值
if (str < end) *str = c;
++ str;
/* put width */
while (--field_width > 0)//如果是左对齐才会进这里,c[空格]
{
if (str < end) *str = ' ';
++ str;
}
continue;
case 's':
s = va_arg(args, char *);
if (!s) s = "(NULL)";
//获取要显示字串的长度
for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
#ifdef RT_PRINTF_PRECISION
//指定显示字串的位数大于0且小于字串的长度,那么将字串的长度改成precision
if (precision > 0 && len > precision) len = precision;
#endif
if (!(flags & LEFT))//非左对齐
{
while (len < field_width--)//len之外的字串填空格
{
if (str < end) *str = ' ';
++ str;
}
}
//将Len长的字串填入Buff
for (i = 0; i < len; ++i)
{
if (str < end) *str = *s;
++ str;
++ s;
}
while (len < field_width--)//左对齐的时候
{
if (str < end) *str = ' ';
++ str;
}
continue;
case 'p':
if (field_width == -1)//没指定输出长度
{
field_width = sizeof(void *) << 1;//8
flags |= ZEROPAD;//填‘0’标志
}
#ifdef RT_PRINTF_PRECISION
str = print_number(str, end,
(long)va_arg(args, void *),
16, field_width, precision, flags);
#else
str = print_number(str, end,
(long)va_arg(args, void *),
16, field_width, flags);
#endif
continue;
case '%':
if (str < end) *str = '%';
++ str;
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default://没有匹配到正确的格式,则%为一个字符
if (str < end) *str = '%';
++ str;
if (*fmt)
{
if (str < end) *str = *fmt;
++ str;
}
else//检测到'\0'(%'\0')说明到字串尾部了,防止越界
{
-- fmt;
}
continue;
}
//能走到下面的有d,i,u,o,x
#ifdef RT_PRINTF_LONGLONG
if (qualifier == 'L') num = va_arg(args, long long);
else if (qualifier == 'l')
#else
if (qualifier == 'l')//long
#endif
{
num = va_arg(args, rt_uint32_t); //long unsigned int
if (flags & SIGN) num = (rt_int32_t)num;//long int
}
else if (qualifier == 'h')//short
{
num = (rt_uint16_t)va_arg(args, rt_int32_t);// unsigend short
if (flags & SIGN) num = (rt_int16_t)num;// signed short
}
else
{
num = va_arg(args, rt_uint32_t);//unsigend int
if (flags & SIGN) num = (rt_int32_t)num; //signed int
}
#ifdef RT_PRINTF_PRECISION
str = print_number(str, end, num, base, field_width, precision, flags);
#else
str = print_number(str, end, num, base, field_width, flags);
#endif
}
if (size > 0)
{
if (str < end) *str = '\0';
else
{
end[-1] = '\0';
}
}
/* the trailing null byte doesn't count towards the total
* ++str;
*/
return str - buf;
}
/**
* This function will fill a formatted string to buffer
*
* @param buf the buffer to save formatted string
* @param size the size of buffer
* @param fmt the format
*/
rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...)
{
rt_int32_t n;
va_list args;
va_start(args, fmt);
n = rt_vsnprintf(buf, size, fmt, args);
va_end(args);
return n;
}
/**
* This function will fill a formatted string to buffer
*
* @param buf the buffer to save formatted string
* @param arg_ptr the arg_ptr
* @param format the format
*/
rt_int32_t rt_vsprintf(char *buf, const char *format, va_list arg_ptr)
{
return rt_vsnprintf(buf, (rt_size_t) - 1, format, arg_ptr);
}
/**
* This function will fill a formatted string to buffer
*
* @param buf the buffer to save formatted string
* @param format the format
*/
rt_int32_t rt_sprintf(char *buf, const char *format, ...)
{
rt_int32_t n;
va_list arg_ptr;
va_start(arg_ptr, format);
n = rt_vsprintf(buf, format, arg_ptr);
va_end(arg_ptr);
return n;
}
/**
* This function will print a formatted string on system console
*
* @param fmt the format
*/
void rt_kprintf(const char *fmt, ...)
{
va_list args;
rt_size_t length;
static char rt_log_buf[RT_CONSOLEBUF_SIZE];
va_start(args, fmt);
/* the return value of vsnprintf is the number of bytes that would be
* written to buffer had if the size of the buffer been sufficiently
* large excluding the terminating null byte. If the output string
* would be larger than the rt_log_buf, we have to adjust the output
* length. */
length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
if (length > RT_CONSOLEBUF_SIZE - 1)
length = RT_CONSOLEBUF_SIZE - 1;
#ifdef RT_USING_DEVICE
if (_console_device == RT_NULL)
{
rt_hw_console_output(rt_log_buf);
}
else
{
rt_uint16_t old_flag = _console_device->open_flag;
_console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
rt_device_write(_console_device, 0, rt_log_buf, length);
_console_device->open_flag = old_flag;
}
#else
rt_hw_console_output(rt_log_buf);
#endif
va_end(args);
}
#endi