2010-03-23 3 views
2

Linux의 직렬 포트에서 데이터를 읽는 프로그램을 작성 중입니다. 데이터는 다음의 프레임 포맷과 다른 디바이스에 의해 전송된다 : 도시 옥텟 1,2- 데이터의 한 종류로 포함C에서 구문 분석 및 데이터 프레임 읽기?

|start | Command | Data    | CRC | End | 
|0x02 | 0x41 | (0-127 octets)  |  | 0x03| 
---------------------------------------------------- 

데이터 필드는 127 개 옥텟을 포함; 옥텟 3,4는 다른 데이터를 포함합니다. 나는

내가 작성 및 리눅스에서 시리얼 포트에서 데이터를 읽는 방법을 알고 이러한 데이터를 얻기 위해 필요하지만, 그것은 단지 작성하고

내 문제 ("ABD"와 같은) 간단한 문자열을 읽는 것입니다 나는 그래서 내가 할 수있는 것을 위와 같이 포맷 된 데이터 프레임을 구문 분석하는 방법을 모르는 것입니다 :

  • 데이터 필드
  • 데이터 옥텟 3,4에서 얻을에 옥텟 1, 2의 데이터를 얻을 수 데이터 필드
  • CRC 필드의 값을 가져 와서 데이터의 일관성을 검사합니다. 여기

읽고에서와 리눅스에서 시리얼 포트에 간단한 문자열을 쓰기 샘플 싹둑 코드 :

int writeport(int fd, char *chars) { 
    int len = strlen(chars); 
    chars[len] = 0x0d; // stick a <CR> after the command 
    chars[len+1] = 0x00; // terminate the string properly 
    int n = write(fd, chars, strlen(chars)); 
    if (n < 0) { 
     fputs("write failed!\n", stderr); 
     return 0; 
    } 
    return 1;                           
} 

int readport(int fd, char *result) { 
    int iIn = read(fd, result, 254); 
    result[iIn-1] = 0x00; 
    if (iIn < 0) { 
     if (errno == EAGAIN) { 
      printf("SERIAL EAGAIN ERROR\n"); 
      return 0; 
     } else { 
      printf("SERIAL read error %d %s\n", errno, strerror(errno)); 
      return 0; 
     } 
    }      
    return 1; 
} 

사람이 몇 가지 아이디어를 가지고하시기 바랍니다 하는가를?

+0

'코드'블록에 코드를 입력하면 읽기가 더 쉬울 것입니다. – KevinDTimm

답변

5

은 1 옥텟 폭 인 char의 배열이다.

는 옥텟 읽기 N 사용 : 그래서
char octet_n = result[n]; 

는 당신이 필요로 원하는 것을 할 수있는 :

// skip the start and command fields 
char *data_field = result + 2; 

int octet_1_2 = data_field[1] | (data_field[2] << 8); 
int octet_3_4 = data_field[3] | (data_field[4] << 8); 

// crc is at byte 128 + 2 = 130 
int crc = result[130]; 

편집 :

int octet_1_2 = data_field[1] | (data_field[2] << 8); 
:이 라인에 대한 설명

당신은 t를 읽고 싶습니다. 하나의 16 비트 워드로 연속 옥텟 하시다 : 옥텟 1의 0 비트 7에 넣어 : 다음

octet_1_2 = data_field[1]; 

당신이 원하는 : octet_1_2 0

  1 
     bits 5  8 7  0 
      -------------------- 
octet_1_2 = | octet 2 | octet 1| 
      -------------------- 

그래서 당신은 비트 7을 먹고 싶어 옥텟 2의 비트 7 : 0을 취해 비트 15 : 8에 넣으십시오. octet_1_2. 당신은 octet_1_2로 결과를 보내고 '왼쪽으로 옥텟이 8 비트를 이동하여이 작업을 수행하고, OR : 내가 위에서처럼

octet_1_2 |= data_field[2] << 8; 

이 두 줄은 하나로 병합 할 수 있습니다.

+1

또한 바이트 스트림의 엔디안을 알아야합니다. @ 네이선은 그의 대답에서 리틀 엔디안을 추측하고있다. –

+0

좋은 지적. 빅 엔디안 인 경우 단순히 인디스를 뒤집으십시오. –

+0

답변 해 주셔서 대단히 감사합니다. 다른 것을 요청하고 싶습니다. 이렇게하면 데이터를 어떻게 얻을 수 있는지 더 설명해주십시오 : int octet_1_2 = data_field [1] | (data_field [2] << 8); int octet_3_4 = data_field [3] | (data_field [4] << 8); 나는 정말로 이해하지 못한다. 고마워요. – ipkiss

0

C에서 형식이 지정된 데이터를 읽는 가장 좋은 방법은 구조를 읽는 것입니다. 프레임 형식을 사용하면 다음을 수행 할 수 있습니다.


typedef struct special_data 
{ 
    char first_data[2]; 
    char second data[2]; 
} special_data_t; 

union data_u 
{ 
    special_data_t my_special_data; 
    char   whole_data[128]; 
}; 

typedef struct data_frame 
{ 
    unsigned char start; 
    unsigned char cmd; 
    union data_u data; 
    unsigned char crc; 
    unsigned char end; 
} data_frame_t; 

void func_read(int fd) 
{ 
    data_frame_t my_data; 

    if (read(fd, &my_data, sizeof(my_data)) != -1) 
    { 
     // Do something 
    } 
    return; 
} 

이렇게하면 구조 필드를 통해 필요한 데이터에 액세스 할 수 있습니다. 첫 번째 구조체와 공용체는 프레임의 데이터 필드에서 필요한 바이트에 액세스하는 데 필요한 도우미 일뿐입니다.

+3

때때로 구조체의 멤버간에 패딩을 추가하여 액세스 성능을 향상시킵니다. 나는 이런 식으로 접근하기 전에 패딩이 사용되지 않는다는 것을 보장하는 컴파일러 pragma를 추가 할 것이다. 그것에 대한 자세한 내용은 Google #pragma pack을 참조하십시오. – Laserallan

+0

+1 laserallan -이 경우 읽기 구조체는 좋은 생각이 아닙니다. – KevinDTimm

+0

@laserallan; 컴파일러가 구조체를 채울 수있는 유일한 이유는 정렬일까요? 왜 문자를 정렬해야합니까? 이 대답이 좋다는 말은 아닙니다. 단지 그것이 반드시 옳지 않다는 것을 말하면서, 그것은 모든 문자들입니다. – falstro