/**
* @file HW_UART_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2026 MZ-ATY
* - This code follows:
* - MZ-ATY Various Contents Joint Statement -
*
* https://mengze.top/MZ-ATY_VCJS
* - CC 4.0 BY-NC-SA -
*
* https://creativecommons.org/licenses/by-nc-sa/4.0/
* - Your use will be deemed to have accepted the terms of this statement.
*
* @brief functions of uart for C platform
*
* @version
* - 1_01_221231 > ATY
* -# Preliminary version, first Release
* - 1_02_240410 > ATY
* -# add multy addr and channel
* -# add lock
* - 1_03_251114 > ATY
* -# remove _printf_ support
* - 1_04_251118 > ATY
* -# finish UartPrintf and test
* @todo over with "\r\n" type
********************************************************************************
*/
#ifndef __HW_UART_ATY_C
#define __HW_UART_ATY_C
#include "HW_UART_ATY.h"
/******************************* For user *************************************/
/******************************************************************************/
/**
* @brief uart send byte and init uart if not initialized
* @param byte byte to send
* @param dev
* @return uint8_t
*/
uint8_t UartSendByte(uint8_t byte, struct HW_UART_ATY_Dev* dev){
__ATY_LOCK(dev);
if(dev->uartInitFlag == 0){
dev->uartInitFlag = 1;
dev->uartInit(dev->rx);
}
// while(dev->rxCount)
// dev->rx[dev->rxCount--] = 0;
dev->uartSendByte(byte);
__ATY_UNLOCK(dev);
return 0;
}
/**
* @brief
*
* @param dev
*/
void UartRxClear(struct HW_UART_ATY_Dev* dev){
if(!dev->rxCount) return;
while(dev->rxCount)
dev->rx[dev->rxCount--] = 0;
}
/**
* @brief uart send bytes
* @param bytes bytes to send
* @param len bytes to send
* @param dev
*/
void UartSendBytes(uint8_t* bytes, uint16_t len, struct HW_UART_ATY_Dev* dev){
while(len--)
UartSendByte(*bytes++, dev);
}
/**
* @brief uart send string
* @param str data to send
* @param dev
*/
void UartSendStr(uint8_t* str, struct HW_UART_ATY_Dev* dev){
while(*str)
UartSendByte(*str++, dev);
}
/**
* @brief uart send float data in specified endian
* @param dataFloat float number
* @param endian
* @param dev
*/
void UartSendFloat(float dataFloat, uint8_t endian, struct HW_UART_ATY_Dev* dev){
union result{
float temp_f;
uint8_t temp_uint8[4];
}resultA, resultB;
resultA.temp_f = dataFloat;
if(endian == 'B'){
resultB.temp_uint8[0] = resultA.temp_uint8[3];
resultB.temp_uint8[1] = resultA.temp_uint8[2];
resultB.temp_uint8[2] = resultA.temp_uint8[1];
resultB.temp_uint8[3] = resultA.temp_uint8[0];
}
else if(endian == 'L'){
resultB.temp_uint8[0] = resultA.temp_uint8[0];
resultB.temp_uint8[1] = resultA.temp_uint8[1];
resultB.temp_uint8[2] = resultA.temp_uint8[2];
resultB.temp_uint8[3] = resultA.temp_uint8[3];
}
UartSendBytes(resultB.temp_uint8, 4, dev);
}
/**
* @brief uart send float data in ASCII character type
* @param dataFloat number to send, use double to get better
* @param DECIMALS_NUM
* @param dev
* @note float and double is the same in C51
*/
void UartSendFloatStr(float dataFloat, uint8_t DECIMALS_NUM, struct HW_UART_ATY_Dev* dev){
uint32_t integerPart, decimalPart;
uint32_t power10 = 1; // Used to compute 10^DECIMALS_NUM
uint8_t i;
// Handle negative numbers
if(dataFloat < 0){
UartSendByte('-', dev);
dataFloat = -dataFloat; // Convert to positive
}
// Extract integer part
integerPart = (uint32_t)dataFloat;
// Compute 10^DECIMALS_NUM
for(i = 0; i < DECIMALS_NUM; i++){
power10 *= 10;
}
// Compute decimal part (avoiding floating-point precision issues, +0.5 for rounding)
decimalPart = (uint32_t)((dataFloat - integerPart) * power10 + 0.5);
// Send integer part
char buf[10]; // Buffer for integer part characters
uint8_t index = 0;
if(integerPart == 0){
buf[index++] = '0'; // Directly send "0"
}
else{
while(integerPart > 0){
buf[index++] = (integerPart % 10) + '0';
integerPart /= 10;
}
// Reverse the integer part before sending
while(index > 0){
UartSendByte(buf[--index], dev);
}
}
// Send decimal point
if(DECIMALS_NUM > 0){
UartSendByte('.', dev);
// Handle leading zeros in the decimal part
for(i = DECIMALS_NUM - 1; i > 0; i--){
if(decimalPart < power10 / 10){
UartSendByte('0', dev); // Send leading zeros
power10 /= 10;
}
}
// Send decimal part
index = 0;
while(decimalPart > 0){
buf[index++] = (decimalPart % 10) + '0';
decimalPart /= 10;
}
while(index > 0){
UartSendByte(buf[--index], dev);
}
}
// Append a space at the end
UartSendByte(' ', dev);
}
/**
* @brief uart receive data process
* @note put at main while
* @param dev
*/
void UartReceiveProcess(struct HW_UART_ATY_Dev* dev){
if(dev->uartInitFlag == 0){
dev->uartInitFlag = 1;
dev->uartInit(dev->rx);
}
if(dev->rcvOverTimeOutCount > dev->rcvOverTimeOutCountNum){
dev->rcvOverTimeOutCount = 0;
if(dev->rxCount != 0){
dev->rcvOverFlag = 0;
dev->uartReceiveProcess_User();
while(dev->rxCount){
dev->rx[dev->rxCount--] = 0;
}
}
}
else
dev->rcvOverTimeOutCount++;
}
// UartPrintf ------------------------------------------------------------------
void __uart_put_uint_base(struct HW_UART_ATY_Dev* dev, uint32_t v, uint32_t base, uint8_t upper){
char buf[32];
uint8_t i = 0;
do{
uint32_t d = v % base;
buf[i++] = (char)(d < 10 ? ('0' + d) : ((upper ? 'A' : 'a') + (d - 10)));
v /= base;
} while(v);
while(i){
UartSendByte((uint8_t)buf[--i], dev);
}
}
void __uart_put_int_dec(struct HW_UART_ATY_Dev* dev, int32_t v){
if(v < 0){
UartSendByte('-', dev);
__uart_put_uint_base(dev, (uint32_t)(-v), 10u, 0u);
}
else{
__uart_put_uint_base(dev, (uint32_t)v, 10u, 0u);
}
}
void __uart_put_float(struct HW_UART_ATY_Dev* dev, double v, int decimals){
if(decimals < 0) decimals = 6;
if(v < 0){ UartSendByte('-', dev); v = -v; }
uint32_t ip = (uint32_t)v;
double frac = v - (double)ip;
uint32_t p10 = 1; for(int i = 0; i < decimals; i++) p10 *= 10u;
uint32_t dp = (uint32_t)(frac * (double)p10 + 0.5);
if(dp >= p10){ dp -= p10; ip += 1u; }
__uart_put_uint_base(dev, ip, 10u, 0u);
if(decimals > 0){
UartSendByte('.', dev);
char buf[16];
int idx = 0;
for(int i = 0; i < decimals; i++){ buf[idx++] = (char)('0' + (dp % 10)); dp /= 10; }
while(idx){ UartSendByte((uint8_t)buf[--idx], dev); }
}
}
void __uart_put_sci(struct HW_UART_ATY_Dev* dev, double v, int decimals){
if(decimals < 0) decimals = 6;
if(v == 0.0){
UartSendByte('0', dev);
if(decimals > 0){
UartSendByte('.', dev);
for(int i = 0; i < decimals; i++) UartSendByte('0', dev);
}
UartSendByte('e', dev);
UartSendByte('+', dev);
UartSendByte('0', dev);
UartSendByte('0', dev);
return;
}
if(v < 0){ UartSendByte('-', dev); v = -v; }
int exp = 0;
if(v >= 10.0){ while(v >= 10.0){ v /= 10.0; exp++; } }
else if(v < 1.0){ while(v < 1.0){ v *= 10.0; exp--; } }
uint32_t ip = (uint32_t)v;
double frac = v - (double)ip;
uint32_t p10 = 1; for(int i = 0; i < decimals; i++) p10 *= 10u;
uint32_t dp = (uint32_t)(frac * (double)p10 + 0.5);
if(dp >= p10){ dp -= p10; ip += 1u; if(ip >= 10u){ ip = 1u; exp++; } }
__uart_put_uint_base(dev, ip, 10u, 0u);
if(decimals > 0){
UartSendByte('.', dev);
char buf[16];
int idx = 0;
for(int i = 0; i < decimals; i++){ buf[idx++] = (char)('0' + (dp % 10)); dp /= 10; }
while(idx){ UartSendByte((uint8_t)buf[--idx], dev); }
}
UartSendByte('e', dev);
char sign = (exp >= 0) ? '+' : '-';
if(exp < 0) exp = -exp;
UartSendByte((uint8_t)sign, dev);
char eb[8];
int eidx = 0;
do{ eb[eidx++] = (char)('0' + (exp % 10)); exp /= 10; } while(exp);
while(eidx < 2) eb[eidx++] = '0';
while(eidx){ UartSendByte((uint8_t)eb[--eidx], dev); }
}
void UartPrintf(struct HW_UART_ATY_Dev* dev, ...){
va_list ap;
va_start(ap, dev);
const char* fmt = va_arg(ap, const char*);
while(*fmt){
char c = *fmt++;
if(c != '%'){
UartSendByte((uint8_t)c, dev);
continue;
}
c = *fmt++;
if(!c) break;
int __aty_width = 0;
int __aty_prec = -1;
while(c >= '0' && c <= '9'){ __aty_width = __aty_width * 10 + (c - '0'); c = *fmt++; }
if(c == '.'){ c = *fmt++; __aty_prec = 0; while(c >= '0' && c <= '9'){ __aty_prec = __aty_prec * 10 + (c - '0'); c = *fmt++; } }
switch(c){
case '%':
UartSendByte('%', dev);
break;
case 'c': {
int v = va_arg(ap, int);
UartSendByte((uint8_t)v, dev);
break;
}
case 's': {
const char* s = va_arg(ap, const char*);
if(!s) s = "(null)";
UartSendStr((uint8_t*)s, dev);
break;
}
case 'd': {
int v = va_arg(ap, int);
__uart_put_int_dec(dev, (int32_t)v);
break;
}
case 'u': {
unsigned int v = va_arg(ap, unsigned int);
__uart_put_uint_base(dev, (uint32_t)v, 10u, 0u);
break;
}
case 'x': {
unsigned int v = va_arg(ap, unsigned int);
__uart_put_uint_base(dev, (uint32_t)v, 16u, 0u);
break;
}
case 'X': {
unsigned int v = va_arg(ap, unsigned int);
__uart_put_uint_base(dev, (uint32_t)v, 16u, 1u);
break;
}
case 'f':
case 'F': {
double dv = va_arg(ap, double);
__uart_put_float(dev, dv, __aty_prec);
break;
}
case 'p': {
void* pv = va_arg(ap, void*);
UartSendStr((uint8_t*)"0x", dev);
__uart_put_uint_base(dev, (uint32_t)pv, 16u, 0u);
break;
}
case 'e': {
double dv = va_arg(ap, double);
__uart_put_sci(dev, dv, __aty_prec);
break;
}
default:
UartSendByte('%', dev);
UartSendByte((uint8_t)c, dev);
break;
}
}
va_end(ap);
}
#ifdef UartPrintf_Test_ATY
/**
* @brief Comprehensive on-board test for UartPrintf, covering all format specifiers
* @note Ensure the serial port is connected and the terminal is open with matching baudrate
* @example Call UartPrintf_Test_All(&HW_UART_ATY_Dev_1) inside main()
*/
void UartPrintf_Test_All(struct HW_UART_ATY_Dev* dev){
/* 1. Basic chars and strings */
UartPrintf(dev, "=== 1. Basic chars and strings ===\r\n");
UartPrintf(dev, "char: %c, %c, %c\r\n", 'A', '0', '\n');
UartPrintf(dev, "str: %s, %s, %s\r\n", "Hello", "", "STC51");
/* 2. Integers (decimal) */
UartPrintf(dev, "=== 2. Integers (decimal) ===\r\n");
UartPrintf(dev, "int: %d, %d, %d, %d\r\n", 0, 123, -456, 2147483647);
UartPrintf(dev, "uint: %u, %u, %u\r\n", 0, 65535, 4294967295UL);
/* 3. Hexadecimal */
UartPrintf(dev, "=== 3. Hexadecimal ===\r\n");
UartPrintf(dev, "lowercase: %x, %x, %x\r\n", 0, 0x5F, 0xDEADBEEF);
UartPrintf(dev, "uppercase: %X, %X, %X\r\n", 0, 0x5F, 0xDEADBEEF);
/* 4. Floating point */
UartPrintf(dev, "=== 4. Floating point ===\r\n");
UartPrintf(dev, "default: %f, %f\r\n", 0.0, -3.1415926);
UartPrintf(dev, "precision: %.2f, %.6f, %.0f\r\n", 3.1415926, 3.1415926, 3.1415926);
UartPrintf(dev, "large: %f\r\n", 1e6);
UartPrintf(dev, "small: %f\r\n", 1e-6);
/* 5. Pointers */
UartPrintf(dev, "=== 5. Pointers ===\r\n");
void* p = (void*)0x1234;
UartPrintf(dev, "ptr: %p\r\n", p);
/* 6. Specials and escapes */
UartPrintf(dev, "=== 6. Special characters ===\r\n");
UartPrintf(dev, "%% %%\r\n");
UartPrintf(dev, "mixed: %d|%u|%x|%X|%c|%s|%f\r\n", -1, 255, 255, 255, 'X', "END", 2.718);
/* 7. Scientific notation */
UartPrintf(dev, "=== 7. Scientific notation ===\r\n");
UartPrintf(dev, "%.2e, %.6e, %.0e\r\n", 12345.6789, 0.000012345, 12345.0);
/* End marker */
UartPrintf(dev, "=== UartPrintf test completed ===\r\n");
}
/**
* @brief Quickly verify UartPrintf basic functions with minimal ROM/RAM usage
*/
void UartPrintf_Test_Quick(struct HW_UART_ATY_Dev* dev){
UartPrintf(dev, "QuickTest: %c %s %d %u %x %X %.3f %p %e\r\n",
'Q',
"OK",
-123,
123,
0xAB,
0xAB,
3.14,
(void*)0x2025,
12345.6789);
}
#endif /* UartPrintf_Test_ATY */
#endif /* __HW_UART_ATY_C */
/************************************ etc *************************************/
/* init */
/* STM32 (Open uart global IT, open rx DMA(Mode Normal, Width Byte) and default DMA IT) */
// Uart ------------------------------------------------------------------------
// #include "HW_UART_ATY.h"
// extern DMA_HandleTypeDef hdma_usart1_rx;
// void UartReceiveProcess_User_1(void);
// void UartInit_1(uint8_t* rx){
// HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
// }
// void UartSendByte_1(uint8_t byte){
// HAL_UART_Transmit(&huart1, (uint8_t*)&byte, 1, 0xFFFF);
// }
// struct HW_UART_ATY_Dev HW_UART_ATY_Dev_1 = {
// // .rx = uartRx1,
// .rx = {0},
// .rxCount = 0,
// .txCount = 0,
// .rcvOverTimeOutCountNum = 1,
// .rcvOverTimeOutCount = 0,
// .rcvOverFlag = 0,
// .uartInitFlag = 0,
// .uartInit = UartInit_1,
// .uartSendByte = UartSendByte_1,
// .uartReceiveProcess_User = UartReceiveProcess_User_1,
// .lock = __ATY_UNLOCKED
// };
// void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t Size){
// if(huart == &huart1){
// HAL_UART_DMAStop(&huart1);
// HW_UART_ATY_Dev_1.rcvOverTimeOutCount = 0;
// HW_UART_ATY_Dev_1.rxCount = UART_RX_MAX_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
// HW_UART_ATY_Dev_1.rcvOverFlag = 0;
// HAL_UARTEx_ReceiveToIdle_DMA(&huart1, HW_UART_ATY_Dev_1.rx, UART_RX_MAX_LEN);
// __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
// }
// }
/* 51 */
/* use */
// void main()
// {
// UartPrintf(&HW_UART_ATY_Dev_1, "\r\nHello word!\r\n",);
// while (1)
// {
// UartReceiveProcess(&HW_UART_ATY_Dev_1);
// }
// }
// /**
// * @brief uart receive data analysis in user define self
// */
// void UartReceiveProcess_User_1(void){
// if(HW_UART_ATY_Dev_1.rx[0] == 'O'
// && HW_UART_ATY_Dev_1.rx[1] == 'K'
// && HW_UART_ATY_Dev_1.rx[2] == '?')
// printf_ATY("OK!");
// if(HW_UART_ATY_Dev_1.rx[0] == 'P'
// && HW_UART_ATY_Dev_1.rx[1] == 'W'
// && HW_UART_ATY_Dev_1.rx[2] == 'R'
// && HW_UART_ATY_Dev_1.rx[3] == 'O'
// && HW_UART_ATY_Dev_1.rx[4] == 'F'
// && HW_UART_ATY_Dev_1.rx[5] == 'F'
// )
// PWR_BTN_Off(&PWR_BTN_ATY_t_1);
//
// // echo back, both type has tested
// UartSendBytes(HW_UART_ATY_Dev_1.rx, HW_UART_ATY_Dev_1.rxCount, &HW_UART_ATY_Dev_1);
// UartPrintf(&HW_UART_ATY_Dev_1, "\r\n%s\r\n", HW_UART_ATY_Dev_1.rx);
//
// if(HW_UART_ATY_Dev_1.rxCount != 0){
// Modbus_Process(HW_UART_ATY_Dev_1.rx, HW_UART_ATY_Dev_1.rxCount, &MODBUS_S_LOW_ATY_Dev_1);
// if(MODBUS_S_LOW_ATY_Dev_1.setFlag == 1){
// MODBUS_S_LOW_ATY_Dev_1.setFlag = 0;
// TransMbRegsToFloat(mbG, &MODBUS_S_LOW_ATY_Dev_1);
// }
// // memcpy((char*)cdcStr, ((const char*)(HW_UART_ATY_Dev_3.rx)), HW_UART_ATY_Dev_3.rxCount);
// // CDC_Transmit_FS(cdcStr, HW_UART_ATY_Dev_3.rxCount);
// // memset(cdcStr, 0, HW_UART_ATY_Dev_3.rxCount);
// // HW_UART_ATY_Dev_3.rxCount = 0;
// }
// }
/******************************************************************************/
/******************************** End Of File *********************************/