Marlin固件获取G代码部分分析
Marlin固件用到的C语言字符串操作函数:
函数原型: char *strchr(const char *str,int c)
参数说明:str为一个字符串的指针,c为一个待查找字符。
函数功能:从字符串str中寻找字符c第一次出现的位置。
返回说明:返回指向第一次出现字符c位置的指针,如果没找到则返回NULL
函数原型: long int strtol (const char* str, char** endptr, int base);
参数说明:str 为要转换的字符串,endstr 为第一个不能转换的字符的指针,base 为字符串 str 所采用的进制。
函数功能: 将字符串转换为长整型数(long) ,一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(’\0’)结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回;若参数endptr为NULL,则会不返回非法字符串
返回说明:返回转换后的长整型数;如果不能转换或者 str 为空字符串,那么返回 0(0L);
函数原型: char *strstr(char *str1, const char *str2);
参数说明:str1: 被查找目标 str2: 要查找对象
函数功能:函数用于判断字符串str2是否是str1的子串
返回说明:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
函数原型: double strtod(const char *nptr,char **endptr);
参数说明: nptr:为要转换的字符串,endstr 为第一个不能转换的字符的指针。
函数功能:将字符串转化为浮点型数。strtod()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,到出现非数字或字符串结束时(’\0’)才结束转换,并将结果返回。
若endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr传回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分。如123.456或123e-2。
返回说明:返回转换后的浮点型数
代码分析
在读取串口信息部分定义了一个环形缓冲区(指令缓冲区),用于存储完整的单条Gcode指令 。
cmdbuffer的二维数组可以存储多条Gcode指令,一维指向整条Gcode指令,二维指向单条Gcode指令中的具体内容 。
static char cmdbuffer[BUFSIZE][MAX_CMD_SIZE];
volatile static bool fromsd[BUFSIZE];
static int bufindr = 0; //环形缓冲区的读取位置(buffer_index_read)
static int bufindw = 0; //环形缓冲区的写入位置(buffer_index_write)
static int buflen = 0; //环形缓冲区中命令的个数
void get_command(void) //读取串口信息
{
// char i;
// int16_t n;
// char time[30];
// unsigned long t;
// int hours, minutes;
/* 当串口收到值且cmdbuffer有空间是时,Gcode命令会被读取到cmdbuffer */
while( MYSERIAL_available() > 0 && buflen < BUFSIZE)
{
serial_char = MYSERIAL_read(); //从串口缓冲区中读取字符
/* 如果读取到‘\n’ 或 '\r' 或 ':'且不是注释 或是超过MAX_CMD_SIZE字节数,即表示一条Gcode指令结束 */
if(serial_char == '\n' ||serial_char == '\r' ||(serial_char == ':' && comment_mode == false) ||serial_count >= (MAX_CMD_SIZE - 1) )
{
/* 如果串口计数为0说明当前行为空行,清除注释标记,退出函数,准备读取新行 */
if(!serial_count) //if empty line
{
comment_mode = false; //for new command
return;
}
/* 结束字符串,为存储下一条指令做准备 */
cmdbuffer[bufindw][serial_count] = 0; //terminate string
/* 当前命令行不是注释 */
if(!comment_mode) //comment_mode 注释,如果不是注释
{
comment_mode = false; //for new command
fromsd[bufindw] = false;
/*
删除了读取标记代码并校对部分的代码,此处为非必要代码
*/
/* 当cmdbuffer读取到G0,G1,G2,G3的指令时,如果系统是停止运作的状态,发送错误信息。如果正常运作则打印0k */
if((strchr(cmdbuffer[bufindw], 'G') != NULL)) //当前字符串中有字符“G”
{
strchr_pointer = strchr(cmdbuffer[bufindw], 'G'); //返回字符G所在位置的指针
switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))) //读取字符G后面的数字
{
case 0:
case 1:
case 2:
case 3:
if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored. //如果打印机由于错误停止,G[0-3]代码被忽略掉。
#ifdef SDSUPPORT
if(card.saving)
break;
#endif //SDSUPPORT
printf(MSG_OK); //打印“OK”
printf("\n");
}
else {
printf(MSG_ERR_STOPPED); //打印 由于错误停止的信息 "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
}
break;
default:
break;
}
}
/* 读取一个指令结束,载入下一个cmdbuffer空间 */
bufindw = (bufindw + 1)%BUFSIZE;
buflen += 1;
}
serial_count = 0; //clear buffer //清除缓冲区
}
else
{
if(serial_char == ';') comment_mode = true; //如果串口读取到;号,说明后面为注释
if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char; //如果不是注释内容,将串口信息存储到缓冲区
}
}
/*
删除了支持SD卡接收部分的代码
*/
}