vasiliok
Joined: 17 May 2011 Posts: 19 Location: Kaunas, Lithuania
|
Quick and Simple RS232 string values parser 'El Parser' |
Posted: Fri Nov 10, 2017 2:06 am |
|
|
Hi All!
There is a great need to transfer values from the PC application to the microcontroller using the RS232 interface in a clear and understandable text format. Something remotely similar to JSON, but much simpler and less versatile.
This firmware called "El Parser" :-) receives string from PC, parses it and extracts values of the tokens transmitted.
Now it works with: boolean, unsigned int8 and int16, signed int8 and int16, string (array of values).
If you have time and desire join and help improve the program code!
Let's create a convenient and versatile parser together!
Please test this firmware and report your results!
String with tokens and values must be in such format:
Code: |
{STRING1=1234567890; BOOL1=true; BOOL2=false; WORD1=12345; CRC=253; WORD2=256; BYTE1=100;TEMPERATURE1=-100; LEVEL1=-32767;}
|
It can contain only one token:
The main structure of string is {TOKEN=<value>;}
Pay attention for tokens and their descripted types, for signed and unsigned values!
Tested with PIC18F46K22 microcontroller.
el_parser.h
Code: |
//////////////////////////////////////////////////////////////////
//// el_parser.h ////
//// ////
//// Author: Igor Shaev ////
//// Date: November 10, 2011 ////
//// (C) Kaunas, Lithuania ////
//////////////////////////////////////////////////////////////////
// built in libraries
#include <string.h>
#include <stdlib.h>
//-----------------------------------------------------------------------------
// TOKEN TYPES
#DEFINE _boolean 1
#DEFINE _int8 2 // UNsigned int8
#DEFINE _int16 3 // UNsigned int16
#DEFINE _strng 4 // string or array of values
#DEFINE _sgnint8 5 // signed int8
#DEFINE _sgnint16 6 // signed int16
// some kind of float type wanted :-)
// please help! :-)
#DEFINE SIZE_TOKEN 15 // Sets the max token length including '\0'
#DEFINE TOTAL_TOKENS 11 // Total number of searchable tokens
#DEFINE SIZE_STRING 10 // Size for STRING type array
// Fill in 'tokens' array with your own used tokens
const char tokens[TOTAL_TOKENS][SIZE_TOKEN]={
"BOOL1=\0", // index 0
"BOOL2=\0", // index 1
"BYTE1=\0", // index 2
"BYTE2=\0", // index 3
"WORD1=\0", // index 4
"WORD2=\0", // index 5
"STRING1=\0", // index 6
"STRING2=\0", // index 7
"CRC=\0", // index 8
"TEMPERATURE1=\0", // index 9
"LEVEL1=\0" // index 10
};
// Specify type of your own tokens here, according to 'tokens' array above
const char token_type[TOTAL_TOKENS]={
_boolean, // index 0
_boolean, // index 1
_int8, // index 2
_int8, // index 3
_int16, // index 4
_int16, // index 5
_strng, // index 6
_strng, // index 7
_int8, // index 8
_sgnint8, // index 9
_sgnint16 // index 10
};
unsigned int8 Token[SIZE_TOKEN]; // Temporary command buffer
//-----------------------------------------------------------------------------
// ------- Real variables to assigned to TOKEN received values ----------------
// The same type of variables as assigned in 'token_type' array
int1 BOOL1;
int1 BOOL2;
unsigned int8 BYTE1;
unsigned int8 BYTE2;
unsigned int16 WORD1;
unsigned int16 WORD2;
char STRING1[SIZE_STRING];
char STRING2[SIZE_STRING];
unsigned int8 CRC;
signed int8 TEMPERATURE1;
signed int16 LEVEL1;
//-----------------------------------------------------------------------------
// Position of item find in 'search_string' function
int loc;
// String to save parsed text value
char value_string[SIZE_STRING];
//dummy variable
unsigned int16 dumm;
// flag to detect negative signed variables
int1 flag_negative;
//-----------------------------------------------------------------------------
|
el_parser.c
Code: |
//////////////////////////////////////////////////////////////////
//// el_parser.c ////
//// ////
//// Author: Igor Shaev ////
//// Date: November 10, 2011 ////
//// (C) Kaunas, Lithuania ////
//// ////
//// Description: Set of functions to parse STRING ////
//// received by RS232 and to assign received values to ////
//// desired variables. ////
//// ////
//// Compiler version: 5.074 ////
//// ////
//// Firmware ver 1.0 ////
//// updated: ---- ////
//// ////
//////////////////////////////////////////////////////////////////
#include <el_parser.h>
//=============================================================================
// Search for '{' and '}' in the Rx buffer array
//
// Function returns:
// 1 - if ready to parse the buffer
// 0 - if not ready
//=============================================================================
unsigned int8 ready_to_parse(){
unsigned int16 i;
unsigned int8 counter=0;
for(i=0;i<buf_max;i++){
if(buffer[i]=='{' || buffer[i]=='}')counter++;
}
if(counter==2)return 1;
else return 0;
}
//=============================================================================
//=============================================================================
//=============================================================================
// Clears Rx buffer (fills with zeroes)
//=============================================================================
void clear_rx_buffer(){
unsigned int16 i;
for(i=0;i<buf_max;i++){
buffer[i] = 0;
}
// rx buffer index
buf_index=0;
}
//=============================================================================
//=============================================================================
//=============================================================================
//Loads token to temporary array
//=============================================================================
void load_token(unsigned int8 index){
unsigned int8 var=0; // temp index for array
memset(Token,NULL,SIZE_TOKEN); // Reset data array index
while((tokens[index][var]!=NULL)&&(var<SIZE_TOKEN)){ // Copy data from main "Strings" to commparing array.
Token[var]=tokens[index][var]; // Copy into temp array the strings from Main Database
var++; // index++
}
}
//=============================================================================
//=============================================================================
//=============================================================================
//Searches token in the rx buffer
// Function returns:
// 1 - if token been found
// 0 - if not
//=============================================================================
int1 search_token(unsigned int8 index){
// Loads into temp array the string to be found
load_token(index);
// Find String or Command in rf buffer
if(STRSTR(buffer,Token)!=NULL)
return(1);
else
return(0);
}
//=============================================================================
//=============================================================================
//=============================================================================
// Used for debugging
// Counts TOKENS found in Rx buffer
//
// Function returns:
// number of TOKENS found
//=============================================================================
unsigned int8 number_of_tokens_found(){
unsigned int8 counter=0;
unsigned int16 i;
for(i=0;i<TOTAL_TOKENS;i++){
//load_token(i);
if(search_token(i)==1)counter++;
}
return counter;
}
//=============================================================================
//=============================================================================
//=============================================================================
// Search string in another string without built-in libraries
//
//
// Function returns: index of found string in another string
// (C) http://www.c4learn.com/c-programs/c-program-to-find-substring-of-string.html
//=============================================================================
signed int16 search_string(char src[], char str[]) {
int i, j, firstOcc;
i = 0, j = 0;
while (src[i] != '\0') {
while (src[i] != str[0] && src[i] != '\0')
i++;
if (src[i] == '\0')
return (-1);
firstOcc = i;
while (src[i] == str[j] && src[i] != '\0' && str[j] != '\0') {
i++;
j++;
}
if (str[j] == '\0')
return (firstOcc);
if (src[i] == '\0')
return (-1);
i = firstOcc + 1;
j = 0;
}
}
//=============================================================================
//=============================================================================
//=============================================================================
void clear_temp_buf(){
unsigned int16 i;
for(i=0;i<buf_max;i++){
temp_buf[i] = 0;
}
}
//=============================================================================
//=============================================================================
//=============================================================================
void copy_to_temp_buf(unsigned int16 from){
unsigned int16 i,index;
// Isvalom laikina masyva
clear_temp_buf();
index = 0;
for(i=from;i<buf_max;i++){
temp_buf[index] = buffer[i];
index++;
}
}
//=============================================================================
//=============================================================================
//=============================================================================
void clear_value_string(){
unsigned int16 i;
for(i=0;i<SIZE_STRING;i++){
value_string[i] = 0;
}
}
//=============================================================================
//=============================================================================
//=============================================================================
void extract_value_string(unsigned int16 til){
unsigned int16 i;
// Clear string where the extracted value will be placed
clear_value_string();
for(i=0;i<(til-1);i++){
value_string[i] = temp_buf[i];
}
}
//=============================================================================
//=============================================================================
//=============================================================================
//
// Searches for token and its value
// Returnes value parsed from string
// This is main parsing function
//=============================================================================
unsigned int16 assign_parsed_int_value(unsigned int8 index){
unsigned int16 result=0;
unsigned int16 j;
char s[2];
load_token(index);
fprintf (PC, "Token '%s'\r\n", Token);
loc = search_string(buffer, Token);
/*
// for debugging purposes
if (loc == -1)
fprintf(PC, "Not found\r\n\r\n");
else
fprintf(PC, "Found at location %d\r\n\r\n", loc + 1);
*/
if(loc != -1){
// Jump forvard behind found token position
j = loc + strlen(Token);
// fprintf(PC, "after token = %Lu\r\n\r\n", j);
// Copying part of buffer[] after found <Token> to temp_buf[] array
copy_to_temp_buf(j);
// fprintf (PC, "temp_buf=:%s:\r\n", temp_buf);
strcpy(s,";");
loc = search_string(temp_buf, s);
/*
// for debugging purposes
if (loc == -1)
fprintf(PC, "; Not found\r\n\r\n");
else
fprintf(PC, "; Found at location %d\r\n\r\n", loc + 1);
*/
// Extracting text value between '=' and ';'
if(loc != -1){
// Is tmp_buf[] --> i value_string[]
extract_value_string(loc + 1);
fprintf (PC, "value '%s'\r\n", value_string);
// assign value depending on type in token_type[] array
switch(token_type[index]){
case 1: //boolean
if(value_string[0]=='t') result = 1;
else result = 0;
break;
case 2: //unsigned int8
result = atoi(value_string);
break;
case 3: //unsigned int16
result = atol(value_string);
break;
case 4: //string(array of values)
// NOTHING TO DO HERE
// the string is in 'value_string' array
// copy 'value_string' to your desired string variable
break;
case 5: // signed int8
if(value_string[0]!='-'){
result = atoi(value_string); // positive value without '-' sign
flag_negative = FALSE;
}else{
memmove(value_string,value_string+1,strlen(value_string)); // negative value
result = atoi(value_string);
flag_negative = TRUE;
}
break;
case 6: // signed int16
if(value_string[0]!='-'){
result = atol(value_string); // positive value without '-' sign
flag_negative = FALSE;
}else{
memmove(value_string,value_string+1,strlen(value_string)); // negative value
result = atol(value_string);
flag_negative = TRUE;
}
break;
}//switch
}//if
}
return result; // unsigned int16 value
}
//=============================================================================
//=============================================================================
|
main.h
Code: |
#include <18F46K22.h>
#device ADC=10
#device PASS_STRINGS=IN_RAM
#use delay(crystal=12MHz)
#define LED_RED PIN_D0
#define LED_YELLOW PIN_D1
#define MYG2 PIN_D2
#define MYG1 PIN_D3
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#use rs232(uart1,baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PC, Errors)
#use rs232(uart2,baud=9600,parity=N,xmit=PIN_D6,rcv=PIN_D7,bits=8,stream=WIFI, Errors)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3,stream=pirmas) //
#use i2c(Master,Fast,sda=PIN_D5,scl=PIN_D6,stream=antras) //
#DEFINE interface_used PC
#DEFINE interrupt_used INT_RDA
#DEFINE buf_max 256 // Rx buffer length
unsigned int8 datain, data_from_WIFI;
// Rx buffer
char buffer[buf_max];
unsigned int8 buf_index=0;
// array for parsing, proccesing and searching
char temp_buf[buf_max];
|
main.c
Code: |
#include <main.h>
#include <el_parser.c>
#include <interrupts.c>
//*****************************************************************************
void main(){
//disable_interrupts(GLOBAL);
set_tris_A(0b00000000);
set_tris_B(0b00000000);
set_tris_C(0b10000000);
set_tris_D(0b10001100);
set_tris_E(0b00000000);
// Pull-up rezistory knopok
// Podkliuchaem po neobhodimosti
//port_b_pullups(0b00001100);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_ccp3(CCP_OFF);
setup_adc_ports(NO_ANALOGS);
SETUP_ADC(ADC_OFF);
delay_ms(2000);
//--------------------------------------------------------------------------
//clear_interrupt(INT_EXT_H2L);
clear_interrupt(INT_RDA);
//clear_interrupt(INT_RDA2);
//enable_interrupts(INT_EXT_H2L);
//EXT_INT_EDGE(H_TO_L);
enable_interrupts(INT_RDA);
//enable_interrupts(INT_RDA2);
enable_interrupts(GLOBAL);
//--------------------------------------------------------------------------
while(TRUE){
// for testing RS232 interface :-)
if(input(MYG1)==0){
output_toggle(LED_YELLOW);
fprintf(PC, "MYG1 pressed successfully!\r\n");
delay_ms(300);
}
// for testing RS232 interface :-)
if(input(MYG2)==0){
output_toggle(LED_RED);
fprintf(WIFI, "MYG2 pressed successfully!\r\n");
delay_ms(300);
}
// Check if values string received and parse it
if(ready_to_parse()){
fprintf(PC, "String received!\r\n");
fprintf(PC, "Tokens qty=%u\r\n\r\n", number_of_tokens_found() );
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(8)){
CRC=assign_parsed_int_value(8); // Token with index8 (CRC) value assign to the real CRC variable
fprintf(PC, "CRC = %u\r\n\r\n", CRC );
}else{ fprintf(PC, "CRC not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(5)){
WORD2=assign_parsed_int_value(5); // Token with index5 (WORD2) value assign to the real WORD2 variable
fprintf(PC, "WORD2 = %Lu\r\n\r\n", WORD2 );
}else{ fprintf(PC, "WORD2 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
// for boolean, int8 and int16 type variables
if(search_token(4)){
WORD1=assign_parsed_int_value(4); // Token with index4 (WORD1) value assign to the real WORD1 variable
fprintf(PC, "WORD1 = %Lu\r\n\r\n", WORD1 );
}else{ fprintf(PC, "WORD1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(1)){
BOOL2=assign_parsed_int_value(1); // Token with index1 (BOOL1) value assign to the real BOOL1 variable
fprintf(PC, "BOOL2 = %u\r\n\r\n", BOOL2 );
}else{ fprintf(PC, "BOOL2 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(3)){
BYTE2=assign_parsed_int_value(3); // Token with index3 (BYTE2) value assign to the real BYTE2 variable
fprintf(PC, "BYTE2 = %u\r\n\r\n", BYTE2 );
}else{ fprintf(PC, "BYTE2 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(2)){
BYTE1=assign_parsed_int_value(2); // Token with index2 (BYTE1) value assign to the real BYTE1 variable
fprintf(PC, "BYTE1 = %u\r\n\r\n", BYTE1 );
}else{ fprintf(PC, "BYTE1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(7)){
dumm=assign_parsed_int_value(7); // Token with index7 (STRING2) value assign to the real STRING2 array
strcpy(STRING2, value_string);
fprintf(PC, "STRING2='%s'\r\n\r\n", STRING2 );
}else{ fprintf(PC, "STRING2 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(6)){
dumm=assign_parsed_int_value(6); // Token with index6 (STRING1) value assign to the real STRING1 array
strcpy(STRING1, value_string);
fprintf(PC, "STRING1='%s'\r\n\r\n", STRING1 );
}else{ fprintf(PC, "STRING1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(0)){
BOOL1=assign_parsed_int_value(0); // Token with index0 (BOOL1) value assign to the real BOOL variable
fprintf(PC, "BOOL1 = %u\r\n\r\n", BOOL1 );
}else{ fprintf(PC, "BOOL1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(9)){
TEMPERATURE1=assign_parsed_int_value(9); // Token with index9 (TEMPERATURE1) value assign to the real TEMPERATURE1 variable
// positive or negative?
if(flag_negative == TRUE)TEMPERATURE1 = TEMPERATURE1 * -1;
fprintf(PC, "TEMPERATURE1 = %d\r\n\r\n", TEMPERATURE1 );
}else{ fprintf(PC, "TEMPERATURE1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Assign parsed value to desired variable if token found
if(search_token(10)){
LEVEL1=assign_parsed_int_value(10); // Token with index10 (LEVEL1) value assign to the real LEVEL1 variable
// positive or negative?
if(flag_negative == TRUE)LEVEL1 = LEVEL1 * -1;
fprintf(PC, "LEVEL1 = %Ld\r\n\r\n", LEVEL1 );
}else{ fprintf(PC, "LEVEL1 not found!\r\n\r\n" );}
//--------------------------------------------------------------------
// Do not forget to clear rx buffer after parsing and assigning is done
clear_rx_buffer();
}
}//WHILE END
}// MAIN END
//*****************************************************************************
|
interrupts.c
Code: |
/*
//************************** INTERRUPTS ***************************************
// 1 hz pulses from RTC ic MCP7940N to RB0
#INT_EXT
void INT0_isr(void){
output_toggle(CPU_LED);
clear_interrupt(INT_EXT);
clear_interrupt(INT_EXT_H2L);
}
//*****************************************************************************
*/
//*****************************************************************************
// RS232, "PC"
#INT_RDA
void RDA_isr(void){
output_toggle(LED_YELLOW);
// Read BYTE from RxD buffer
datain = fgetc(interface_used);
buffer[buf_index] = datain;
buf_index++;
if(buf_index == buf_max) buf_index=0;
clear_interrupt(interrupt_used);
}
//*****************************************************************************
//*****************************************************************************
// RS232 "ESP8266 wifi modulis"
#INT_RDA2
void RDA2_isr(void){
output_toggle(LED_RED);
data_from_WIFI = fgetc(WIFI);
//WIFI reply to PC console if enabled (DEBG=1)
fputc(data_from_WIFI,PC);
/*
Rec_Buf[buf_index] = data_from_WIFI;
buf_index++;
if(buf_index>=(Buf_Max-1)){
buf_index = 0;
}
flag_received_WIFI = 1;
*/
clear_interrupt(INT_RDA2);
}
//*****************************************************************************
/*
//*****************************************************************************
// CPU_LED blinker and hardware PULSE COUNTER reader
#INT_TIMER6
void TIMER6_isr(void){
timerio_daliklis++;
if (timerio_daliklis == 50){ //~1sek periodas
timerio_daliklis=0;
}
}
//*****************************************************************************
*/
|
|
|