C LPT并口回路测试

发布时间:2024年01月20日

ch384并口测试程序源代码

/*
 * parport factory test utility.
 *
 * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd.
 * Web:     http://wch.cn
 * Author:  WCH <tech@wch.cn>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Cross-compile with cross-gcc -I /path/to/cross-kernel/include
 *
 * V1.0 - initial version
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/ioctl.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
#include <getopt.h>
 
#define GET_BIT(x, y)	     ((x >> y) & 0x01) /* get y bit value of x */
#define CTRL_REG_INITVAL_OUT 0xc0	       /* control reg value(allow D7-D0 output) */
#define CTRL_REG_INITVAL_IN  0xe0	       /* control reg value(forbid D7-D0 output) */
 
static unsigned char ctrlval = 0;
static char device_name[20];
 
/**
 * ctrl_reg_update: update PCR reg
 * @fd: file descriptor
 * @mask: bits to update
 * @val: 0->clear, 1->set
 */
void ctrl_reg_update(int fd, unsigned char mask, unsigned char val)
{
	int ret;
 
	ctrlval &= ~mask;
	ctrlval |= val & mask;
 
	ret = ioctl(fd, PPWCONTROL, &ctrlval);
	if (ret < 0) {
		perror("ioctl");
		return;
	}
}
 
/**
 * data_line_init: data signals direction initialization
 * @fd: file descriptor
 * @dir: direction value
 * 
 * The function return 0 if successful, others if fail.
 */
int data_line_init(int fd, int dir)
{
	int ret;
 
	if (dir == 0)
		ctrlval = CTRL_REG_INITVAL_IN;
	else
		ctrlval = CTRL_REG_INITVAL_OUT;
 
	ret = ioctl(fd, PPWCONTROL, &ctrlval);
	if (ret < 0) {
		perror("ioctl");
		return -1;
	}
	return 0;
}
 
/**
 * data_reg_read: read data signals
 * @fd: file descriptor
 * 
 * The function return positive if successful, negative if fail.
 */
unsigned char data_reg_read(int fd)
{
	int ret;
	unsigned char data_r;
 
	ret = ioctl(fd, PPRDATA, &data_r);
	if (ret < 0) {
		perror("ioctl");
		return -1;
	}
	return data_r;
}
 
/**
 * print_err_msg: print message according to error code
 * @err_code: error number
 * 
 */
static void print_err_msg(int err_code)
{
	switch (err_code) {
	case 0:
		printf("[error code: %d] STB-D0 ERROR\n", err_code);
		break;
	case 1:
		printf("[error code: %d] AFD-D1 ERROR\n", err_code);
		break;
	case 2:
		printf("[error code: %d] INIT-D2 ERROR\n", err_code);
		break;
	case 3:
		printf("[error code: %d] SIN-D3 ERROR\n", err_code);
		break;
	case 4:
		printf("[error code: %d] D6-ERR ERROR\n", err_code);
		break;
	case 5:
		printf("[error code: %d] D4-SELT ERROR\n", err_code);
		break;
	case 6:
		printf("[error code: %d] D5-PE ERROR\n", err_code);
		break;
	case 7:
		printf("[error code: %d] D6-ACK ERROR\n", err_code);
		break;
	case 8:
		printf("[error code: %d] D7-BUSY ERROR\n", err_code);
		break;
	default:
		break;
	}
}
 
/**
 * check_result: detect whether the current register value matches the target value related bits, and print in case of error
 * @type: test type, 0x01: control line output, data line input, 0x02: data line output, status line input
 * @val: current register value
 * @cmp_val: target register value
 * 
 * The function return 0 if successful, negative if fail.
 */
static int check_result(int type, unsigned char val, unsigned char cmp_val)
{
	int i;
	int ret = 0;
 
	if (type == 0x01) {
		for (i = 0; i < 4; i++) {
			if (GET_BIT(val, i) != GET_BIT(cmp_val, i)) {
				ret = -1;
				print_err_msg(i);
			}
		}
	} else if (type == 0x02) {
		for (i = 3; i < 8; i++) {
			if (GET_BIT(val, i) != GET_BIT(cmp_val, i)) {
				ret = -1;
				print_err_msg(i + 1);
			}
		}
	} else {
		printf("type error.n");
		return -1;
	}
 
	return ret;
}
 
static const struct option lopts[] = {
	{ "device name", required_argument, 0, 'd' },
	{ "start test", no_argument, 0, 's' },
	{ "view the usage method", no_argument, 0, 'h' },
	{ NULL, 0, 0, 0 },
};
 
static void print_usage(const char *prog)
{
	printf("Usage: %s [-dsh]\n", prog);
	puts("  -d device name\n"
	     "  -s start test\n"
	     "  -h view the usage method");
	exit(1);
}
 
static void help_msg(void)
{
	puts("Pin connection mode of parport test:\n"
	     "test1(PDR OUT/PSR IN): D6-ERR D4-SELT D5-PE D6-ACK\n"
	     "test2(PCR OUT/PIR IN): STB-D0 AFD-D1 INIT-D2 SIN-D3 D7-BUSY");
	exit(1);
}
 
static void parse_opts(int argc, char *argv[])
{
	char c;
 
	printf("argc=%d add by wyf\n",argc);
	if (argc != 4)
		print_usage(argv[0]);
 
	while (1) {
		c = getopt_long(argc, argv, "d:sh", lopts, NULL);
		//if (c == -1)
		if (c == 255)
			break;
 
		switch (c) {
		case 'd':
			memcpy(device_name, argv[2], strlen(argv[2]));
			break;
		case 's':
			printf("start test...\n");
			break;
		case 'h':
			help_msg();
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}
 
int main(int argc, char **argv)
{
	int fd;
	int retval;
	int ret_check1, ret_check2, ret_check3, ret_check4;
	unsigned char data_w, status_r;
 
	parse_opts(argc, argv);
 
	/* Open parport device */
	fd = open(device_name, O_RDWR);
	if (fd < 0) {
		perror("open");
		return -1;
	}
 
	/* Claim the port */
	if ((retval = ioctl(fd, PPCLAIM)) < 0) {
		perror("PPCLAIM failed");
		goto exit;
	}
 
	/* Set the direction of D0-D7 to output */
	if ((retval = data_line_init(fd, 0x01)) < 0)
		goto exit;
 
	/* Set D0-D7 output low level */
	data_w = 0x00;
	if ((retval = ioctl(fd, PPWDATA, &data_w)) < 0) {
		perror("PPWDATA ioctl");
		goto exit;
	}
 
	/* Read BUSY, ACK, PE, SELT and ERR signal, judge whether they are all low */
	if ((retval = ioctl(fd, PPRSTATUS, &status_r)) < 0) {
		perror("PPRSTATUS ioctl");
		goto exit;
	}
	ret_check1 = check_result(0x02, status_r, 0x87);
 
	/* Set D4-D7 output high level */
	data_w = 0xf0;
	if ((retval = ioctl(fd, PPWDATA, &data_w)) < 0) {
		perror("PPWDATA ioctl");
		goto exit;
	}
 
	/* Read BUSY, ACK, PE, SELT and ERR signal, judge whether they are all high */
	if ((retval = ioctl(fd, PPRSTATUS, &status_r)) < 0) {
		perror("PPRSTATUS ioctl");
		goto exit;
	}
	ret_check2 = check_result(0x02, status_r, 0x7b);
 
	/* Set the direction of D0-D7 to input */
	if ((retval = data_line_init(fd, 0x00)) < 0)
		goto exit;
 
	/* Set SIN, INIT, AFD and STB output low level */
	ctrl_reg_update(fd, 0x0f, 0x0b);
 
	/* Read D0-D4 signal, judge whether they are all low */
	ret_check3 = check_result(0x01, data_reg_read(fd), 0xf0);
 
	/* Set SIN, INIT, AFD and STB output high level */
	ctrl_reg_update(fd, 0x0f, 0x04);
 
	/* Read D0-D4 signal, judge whether they are all high */
	ret_check4 = check_result(0x01, data_reg_read(fd), 0xff);
 
	if ((ret_check1 == 0) && (ret_check2 == 0) && (ret_check3 == 0) && (ret_check4 == 0))
		printf("Parport pin test passed\n");
	else
		printf("Parport pin test failed\n");
 
exit:
	/* Release the port */
	if (ioctl(fd, PPRELEASE) < 0)
		perror("PPRELEASE failed");
 
	close(fd);
 
	return retval;
}

其它PARPART源代码:

main.c

#include <testlpt.h>

int fd;
unsigned char data=0x41;
int counter=0;

int main(int argc, char **argv)
{
    pthread_t id[1]; 
    pthread_attr_t attr;        

    if ((fd=open(DEVICE, O_RDWR | O_NOCTTY )) < 0) {
        fprintf(stderr, "can not open %s\n", DEVICE);
        return 5;
    }
    int  mode = IEEE1284_MODE_NIBBLE;
     int res=ioctl(fd, PPSETMODE, &mode);

     if( res== -1 ) {
    fprintf(stdout,"PPSETMODE ERROR\n");
  }
unsigned int modes;
     res=ioctl(fd, PPGETMODE, &modes);  
  if( res ==0 ) {
    fprintf(stdout,"MODES= 0x%02x\n", modes);
  }

#if 1
  while (claim_port() <0 ){
fprintf (stdout,"Claimt port error = %d\n",0);
sleep(1);
continue;
}
#endif

pthread_attr_init(&attr);
pthread_mutex_init(&lock, NULL);

#if 1
    if (pthread_create(&id[0],0,&write_data,NULL)){
perror("pthread create error!");
    }
    if (pthread_create(&id[1],0,&reads_data,NULL)){
perror("pthread create error!");
    }

if (pthread_join(id[0],NULL)) {
        perror("pthread exit error!");
        }
if (pthread_join(id[1],NULL)) {
        perror("pthread exit error!");
        }

    ioctl(fd, PPRELEASE);
    close(fd);
    exit(EXIT_SUCCESS);
#endif
}

int claim_port() {
  if (ioctl(fd, PPCLAIM) < 0) {
//  if (ioctl(fd, PPEXCL) < 0) {
  int errsv = errno;
  fprintf(stdout,"CLAIM errno %s \n",strerror(errsv));
        close(fd);
        return -1;
    }
        return 0;
}

read.c源代码:

/* read.c */

#include <sys/select.h>
#include "testlpt.h"



void *reads_data() {

unsigned char data;
data='\0';


int res=0;

fd_set rfds;

counter =0;

for(;;) {
struct timeval tv;  
tv.tv_sec = 0;
tv.tv_usec = 100;
errno =0;



FD_ZERO(&rfds);
FD_SET(fd, &rfds);

#if 1
    int mode=0x00;
    res=ioctl(fd, PPDATADIR, &mode);
  res=select (fd + 1, &rfds, (fd_set *)NULL, (fd_set *)NULL, &tv);
    fprintf(stdout,"res select = %d counter = %d \n",res,counter);
  if( res== -1 ) {
    fprintf(stdout,"End Read by select \n");
       continue;

    } else if (res == 0){
    fprintf(stdout,"Select timeout\n");
    } else {
    counter++;
    if ( FD_ISSET(fd , &rfds ) ) {
    res=ioctl(fd, PPRDATA, &data);  /* now fetch the data! */


    if (res < 0) {
    fprintf(stdout,"End Read by end of array\n");
    break;
        }
    }
   }
#endif  


    fflush(stdout);
    usleep(USLEEP);

 if (( data > 0x40 ) && ( data < 0x5B)) {
    fprintf(stdout,"counter = %d data = %c\n",counter,data);
    }
counter++;
}

FD_ZERO(&rfds);
    fprintf(stdout,"End Read\n");
pthread_exit(0);
}

write.c 源代码:

#include "testlpt.h"
#include <sys/types.h>

/* example how to write data */
void  *write_data() {
unsigned char status='\0';

  for(int i=0;i<SIZE_BUF;i++)  {


    int mode=0xFF;
int     res=ioctl(fd, PPDATADIR, &mode);

      fprintf(stdout,"Data= %c\n",data);
#if 1
#endif

counter=counter+0;
  res=ioctl(fd, PPWDATA, &data);

      if (res < 0)   {
       fprintf(stdout,"Error write (%d)(%s)\n",errno,strerror(errno));
       break;
    }
  data++;
  usleep(USLEEP);
   }
 int res=ioctl(fd, PPRELEASE);
 if (res < 0 ){
fprintf(stdout,"Release error \n"); 
 }
pthread_exit(0);
}

/* example how to read the status lines. */
int status_pins(int fd)
{
    unsigned char val;

    int res=ioctl(fd, PPRSTATUS, &val);
    if (res <0){
        fprintf(stdout,"PPRSTATUS ERROR res = %d\n",res);
        return -1;
    }
// val ^= PARPORT_STATUS_BUSY; /* /BUSY needs to get inverted */
fprintf(stdout,"ERROR  = 0x%02x \n", (val & (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY))); //==PARPORT_STATUS_ERROR)?"HI":"LO",val ^= PARPORT_STATUS_BUSY);
fprintf(stdout,"BUSY = 0x%02x \n", (val & PARPORT_STATUS_BUSY)); //==PARPORT_STATUS_ERROR)?"HI":"LO",val ^= PARPORT_STATUS_BUSY);
fprintf(stdout,"SELECT  = 0x%02x \n", (val & PARPORT_STATUS_SELECT)); //==PARPORT_STATUS_ERROR)?"HI":"LO",val ^= PARPORT_STATUS_BUSY);
fprintf(stdout,"ACK  = 0x%02x \n", (val & PARPORT_STATUS_ACK)); //==PARPORT_STATUS_ERROR)?"HI":"LO",val ^= PARPORT_STATUS_BUSY);
}

testlpt.h头文件

#ifndef _TESTLPT_H
#define _TESTLPT_H

//#include <stdio.h>
#include <stdio.h>
#include <fcntl.h>      
#include <sys/types.h>      
#include <sys/stat.h>       
#include <sys/ioctl.h>
#include <linux/parport.h>
#include <linux/ppdev.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
//#include <asm/io.h>
//#include "/usr/src/linux-headers-5.4.18-35/arch/arm/include/asm/io.h"
#include "/usr/src/linux-headers-5.4.18-53/arch/arm/include/asm/io.h"
#include <errno.h>
#include <error.h>
#include <string.h> 

#define DEVICE "/dev/parport0"
//#define DEVICE "/dev/lp0"
#define SIZE_BUF 26
#define USLEEP 1000
#define TIMEOUT 1

#include <poll.h>

#include <sys/epoll.h>

void *reads_data();
void *write_data();

int claim_port ();
int port_select(int fd);

extern int fd;
extern unsigned char data;
extern int counter;

static pthread_mutex_t lock;

#endif /* testlpt.h */

文章来源:https://blog.csdn.net/u013934107/article/details/135713017
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。