ARM embedded application debugging input simulator writing test simulation function

Publisher:tetsikaLatest update time:2018-04-13 Source: eefocusKeywords:ARM Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Customize the myprintk function to print information to the mymsg file:

                        Custom print function caches print data to a ring buffer

================================================== ==================

Touch screen driver source code:

 

#include "linux/errno.h"

#include "linux/kernel.h"

#include "linux/module.h"

#include "linux/slab.h"

#include "linux/input.h"

#include "linux/init.h"

#include "linux/serio.h"

#include "linux/delay.h"

#include "linux/platform_device.h"

#include "linux/clk.h"

#include "asm/io.h"

#include "asm/irq.h"

#include "asm/uaccess.h"

 

#include "asm/plat-s3c24xx/ts.h"

 

#include "asm/arch/regs- adc .h"

#include "asm/arch/regs-gpio.h"

 

struct s3c_ts_regs {

   unsigned long adccon;

   unsigned long adctsc;

   unsigned long adcdly;

   unsigned long adcdat0;

   unsigned long adcdat1;

   unsigned long adcupdn;

};

 

static struct input_dev *s3c_ts_dev;

static volatile struct s3c_ts_regs *s3c_ts_regs;

 

static struct timer_list ts_timer;

 

#define MYLOG_BUF_LEN (1024*1024)

#define INPUT_REPLAY 0

#define INPUT_TAG 1

 

static char *replay_buf;

static int replay_r = 0;

static int replay_w = 0;

static int major = 0;

static struct class *cls;

static struct timer_list replay_timer;

 

extern int myprintk(const char *fmt, ...);

 

static ssize_t replay_write(struct file * file, const char __user *buf, size_t size, loff_t *offset)

{

   int err;

   

   // Write the data passed by the application to replay_buf //

   if (replay_w + size "= MYLOG_BUF_LEN)

   {

      printk("replay_buf full!\n");

      return -EIO;

   }

   

   err = copy_from_user(replay_buf + replay_w, buf, size);

   if (err)

   {

      return -EIO;

   }

   else

   {

      replay_w += size;

   }

 

   return size;

}

 

// app: ioctl(fd, CMD, ..); //

static int replay_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

   char buf[100];

   switch (cmd)

   {

      case INPUT_REPLAY:

      {

         // Start playback: report events based on the data in replay_buf//

         replay_timer.expires = jiffies + 1;

         printk("replay_ioctl add_timer\n");

         add_timer(&replay_timer);

         break;

      }

      case INPUT_TAG:

      {

         copy_from_user(buf, (const void __user *)arg, 100);

         buf[99] = '\0';

         myprintk("%s\n", buf);

         break;

      }

   }

   

   return 0;

}

 

// Return value: 0 - no data //

static int replay_get_line(char *line)

{

   int i = 0;

   

   //Eat leading spaces and carriage returns//

   while (replay_r "= replay_w)

   {

      if ((replay_buf[replay_r] == ' ') || (replay_buf[replay_r] == '\n') || (replay_buf[replay_r] == '\r') || (replay_buf[replay_r] == ' \t'))

         replay_r++;

      else

         break;

   }

 

   while (replay_r "= replay_w)

   {

      if ((replay_buf[replay_r] == '\n') || (replay_buf[replay_r] == '\r'))

         break;

      else

      {

         line[i] = replay_buf[replay_r];

         replay_r++;   

         i++;

      }

   }

 

   line[i] = '\0';

   return i;   

}

 

static void input_replay_timer_func(unsigned long data)

{

   // Take some data out of replay_buf and report it 

   // Read the first row of data, determine the time value, and report the first row

   // Continue reading the next row of data. If its time is equal to the time of the first row, report it.

   // Otherwise: mod_timer  

   //

 

   unsigned int time;

   unsigned int type;

   unsigned int code;

   int val;

 

   static unsigned int pre_time = 0, pre_type = 0, pre_code = 0;

   static int pre_val = 0;

 

   static int cnt = 0;

 

   

   char line[100];

   int ret;

 

   //printk("input_replay_timer_func : %d\n", cnt++);

 

   if (pre_time != 0)

   {

      // Report event//

      input_event(s3c_ts_dev, pre_type, pre_code, pre_val);

   }

   

   while (1)

   {

      ret = replay_get_line(line);

      if (ret == 0)

      {

         printk("end of input replay\n");

         del_timer(&replay_timer);

         pre_time = pre_type = pre_code = 0;

         pre_val = 0;

         replay_r = replay_w = 0;

         break;

      }

 

      // Data processing//

      time = 0;

      type = 0;

      code = 0;

      val = 0;

      sscanf(line, "%x %x %x %d", &time, &type, &code, &val);

 

      //printk("%x %x %x %d\n", time, type, code, val);

      

      if (!time && !type && !code && !val)

         continue;

      else

      {

         if ((pre_time == 0) || (time == pre_time))

         {

            // Report event//

            input_event(s3c_ts_dev, type, code, val);

            

            if (pre_time == 0)

               pre_time = time;

         }

         else

         {

            // According to the time of the next data to be reported mod_timer //

            mod_timer(&replay_timer, jiffies + (time - pre_time));            

 

            pre_time = time;

            pre_type = type;

            pre_code = code;

            pre_val = val;

            

            break;

         }

      }

   }

   

}

 

static struct file_operations replay_fops = {

   .owner = THIS_MODULE,

   .write = replay_write,

   .ioctl = replay_ioctl,

};

 

static void enter_wait_pen_down_mode(void)

{

   s3c_ts_regs-"adctsc = 0xd3;

}

 

static void enter_wait_pen_up_mode(void)

{

   s3c_ts_regs - "adctsc = 0x1d3;

}

 

static void enter_measure_xy_mode(void)

{

   s3c_ts_regs-"adctsc = (1""3)|(1""2);

}

 

static void start_adc(void)

{

   s3c_ts_regs-"adccon |= (1""0);

}

 

void write_input_event_to_file(unsigned int time, unsigned int type, unsigned int code, int val)

{

   myprintk("0xx 0xx 0xx %d\n", time, type, code, val);   

}

 

static int s3c_filter_ts(int x[], int y[])

{

#define ERR_LIMIT 10

 

   int  avr_x , avr_y;

   int det_x, det_y;

 

   avr_x = (x[0] + x[1])/2;

   avr_y = (y[0] + y[1])/2;

 

   det_x = (x[2] " avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);

   det_y = (y[2] " avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);

 

   if ((det_x " ERR_LIMIT) || (det_y " ERR_LIMIT))

      return 0;

 

   avr_x = (x[1] + x[2])/2;

   avr_y = (y[1] + y[2])/2;

 

   det_x = (x[3] " avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);

   det_y = (y[3] " avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);

 

   if ((det_x " ERR_LIMIT) || (det_y " ERR_LIMIT))

      return 0;

   

   return 1;

}

 

static void s3c_ts_timer_function(unsigned long data)

{

   if (s3c_ts_regs-"adcdat0 & (1""15))

   {

      // Already released: report and print to proc  

       * jiffies, type, code, value

       //

      input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);

      write_input_event_to_file(jiffies, EV_ABS, ABS_PRESSURE, 0);

      

      input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

      write_input_event_to_file(jiffies, EV_KEY, BTN_TOUCH, 0);

 

      input_sync(s3c_ts_dev);

      write_input_event_to_file(jiffies, EV_SYN, SYN_REPORT, 0);

      

      enter_wait_pen_down_mode();

   }

   else

   {

      //Measure X/Y coordinates//

      enter_measure_xy_mode();

      start_adc();

   }

}

 

 

static irqreturn_t pen_down_up_irq(int irq, void *dev_id)

{

   if (s3c_ts_regs-"adcdat0 & (1""15))

   {

      //printk("pen up\n");

      input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);

      write_input_event_to_file(jiffies, EV_ABS, ABS_PRESSURE, 0);

 

      input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

      write_input_event_to_file(jiffies, EV_KEY, BTN_TOUCH, 0);

 

      input_sync(s3c_ts_dev);

      write_input_event_to_file(jiffies, EV_SYN, SYN_REPORT, 0);

 

      enter_wait_pen_down_mode();

   }

   else

   {

      //printk("pen down\n");

      //enter_wait_pen_up_mode();

      enter_measure_xy_mode();

      start_adc();

   }

   return IRQ_HAND LED ;

}

 

static irqreturn_t adc_irq(int irq, void *dev_id)

{

   static int cnt = 0;

   static int x[4], y[4];

   int adcdat0, adcdat1;

   

   

   //Optimization measure 2: If the stylus is released when ADC is completed, the result will be discarded //

   adcdat0 = s3c_ts_regs-"adcdat0;

   adcdat1 = s3c_ts_regs-"adcdat1;

 

   if (s3c_ts_regs-"adcdat0 & (1""15))

   {

      // Already released//

      cnt = 0;

      input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);

      write_input_event_to_file(jiffies, EV_ABS, ABS_PRESSURE, 0);

      

      input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

      write_input_event_to_file(jiffies, EV_KEY, BTN_TOUCH, 0);

      

      input_sync(s3c_ts_dev);

      write_input_event_to_file(jiffies, EV_SYN, SYN_REPORT, 0);

      

      enter_wait_pen_down_mode();

   }

   else

   {

      // printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);

      //Optimization measure 3: Calculate the average value by multiple measurements//

      x[cnt] = adcdat0 & 0x3ff;

      y[cnt] = adcdat1 & 0x3ff;

      ++cnt;

      if (cnt == 4)

      {

         //Optimization measure 4: software filtering//

         if (s3c_filter_ts(x, y))

         {         

            //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[ 1]+y[2]+y[3])/4);

            input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);

            write_input_event_to_file(jiffies, EV_ABS, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);

 

            input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);

            write_input_event_to_file(jiffies, EV_ABS, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);

            

            input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);

            write_input_event_to_file(jiffies, EV_ABS, ABS_PRESSURE, 1);

 

            input_report_key(s3c_ts_dev, BTN_TOUCH, 1);

            write_input_event_to_file(jiffies, EV_KEY, BTN_TOUCH, 1);

 

            input_sync(s3c_ts_dev);

            write_input_event_to_file(jiffies, EV_SYN, SYN_REPORT, 0);

         }

         cnt = 0;

         enter_wait_pen_up_mode();

 

         // Start the timer to handle long press/slide situations //

         mod_timer(&ts_timer, jiffies + HZ/100);

      }

      else

      {

         enter_measure_xy_mode();

         start_adc();

      }      

   }

   

   return IRQ_HANDLED;

}

 

static int s3c_ts_init(void)

{

   struct clk* clk;

 

   replay_buf = kmalloc(MYLOG_BUF_LEN, GFP_KERNEL);

   if (!replay_buf)

   {

      printk("can't alloc for mylog_buf\n");

      return -EIO;

   }

 

   

   // 1. Allocate an input_dev structure//

   s3c_ts_dev = input_allocate_device();

 

   // 2. Settings //

   // 2.1 What kind of events can be generated//

   set_bit(EV_KEY, s3c_ts_dev-"evbit);

   set_bit(EV_ABS, s3c_ts_dev-"evbit);

 

   // 2.2 Which events of this type can be generated//

   set_bit(BTN_TOUCH, s3c_ts_dev-"keybit);

 

   input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);

   input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);

   input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

 

 

   // 3. Register //

   input_register_device(s3c_ts_dev);

 

   // 4. Hardware related operations//

   // 4.1 Enable clock (CLKCON[15]) //

   clk = clk_get(NULL, "adc");

   clk_enable(clk);

   

   // 4.2 Set the ADC/TS register of S3C2440 //

   s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));

 

   // bit[14] : 1-A/D converter prescaler enable

    * bit[13:6]: A/D converter prescaler value,

    * 49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz

    * bit[0]: A/D conversion starts by enable. Set to 0 first

    //

   s3c_ts_regs-"adccon = (1""14)|(49""6);

 

   r equ est_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);

   request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);

 

   //Optimization measure 1: 

    * Set ADCDLY to the maximum value, which will cause the IRQ_TC interrupt to be issued after the voltage stabilizes

    //

   s3c_ts_regs - "adcdly = 0xffff;

 

   // Optimization measure 5: Use timer to handle long press and sliding

    * 

    //

   init_timer(&ts_timer);

   ts_timer.function = s3c_ts_timer_function;

   add_timer(&ts_timer);

 

   enter_wait_pen_down_mode();

 

   major =  register_chrdev (0, "input_replay", &replay_fops);

 

   cls = class_create(THIS_MODULE, "input_replay");

   device_create(cls, NULL, MKDEV(major, 0), "input_emu"); // /dev/input_emu //

 

   init_timer(&replay_timer);

   replay_timer.function = input_replay_timer_func;

   //add_timer(&replay_timer);

   

   return 0;

}

 

static void s3c_ts_exit(void)

{

   //del_timer(&replay_timer);

   

   kfree(replay_buf);

   device_destroy(cls, MKDEV(major, 0));

   class_destroy(cls);

   unregister_chrdev(major, "input_replay");

   

   free_irq(IRQ_TC, NULL);

   free_irq(IRQ_ADC, NULL);

   iounmap(s3c_ts_regs);

   input_unregister_device(s3c_ts_dev);

   input_free_device(s3c_ts_dev);

   del_timer(&ts_timer);

}

 

module_init(s3c_ts_init);

module_exit(s3c_ts_exit);

 

 

MODULE_LICENSE("GPL");

 

================================================== ================

test program:

 

#include "sys/types.h"

#include "sys/stat.h"

#include "fcntl.h"

#include "stdio.h"

#include "poll.h"

#include "signal.h"

#include "sys/types.h"

#include "unistd.h"

#include "fcntl.h"

#include "stdlib.h"

#include "string.h"

 

#define INPUT_REPLAY 0

#define INPUT_TAG 1

 

// Usage:

//./input_replay write "file"

// ./input_replay replay

// ./input_repaly tag "string"

//

 

void print_usage(char *file)

{

   printf("Usage:\n");

   printf("%s write "file"\n", file);

   printf("%s replay\n", file);

   printf("%s tag "string"\n", file);

}

 

int main(int argc, char **argv)

{

   int fd;

   int fd_data;

   int buf[100];

   int len;

   

   if (argc != 2 && argc != 3)

   {

      print_usage(argv[0]);

      return -1;

   }

 

   fd = open("/dev/input_emu", O_RDWR);

   if (fd " 0)

   {

      printf("can't open /dev/input_emu\n");

      return -1;

   }

 

   if (strcmp(argv[1], "replay") == 0)

   {

      ioctl(fd, INPUT_REPLAY);

   }

   else if (strcmp(argv[1], "write") == 0)

   {

      if (argc != 3)

      {

         print_usage(argv[0]);

         return -1;

      }

 

      fd_data = open(argv[2], O_RDONLY);

      if (fd_data " 0)

      {

         printf("can't open %s\n", argv[2]);

         return -1;

      }

 

      while (1)

      {

         len = read(fd_data, buf, 100);

         if (len == 0)

         {

            printf("wite ok\n");

            break;

         }

         else

         {

            write(fd, buf, len);            

         }

      }

   }

   else if (strcmp(argv[1], "tag") == 0)

   {

      if (argc != 3)

      {

         print_usage(argv[0]);

         return -1;

      }

      ioctl(fd, INPUT_TAG, argv[2]);

   }

   else

   {

      print_usage(argv[0]);

      return -1;

   }

   return 0;  

}

 

================================================== ==============

Analysis:

When the touch screen is pressed, the event is reported by printing the pressing time, type, etc. into a specified file, such as /proc/mymsg, and then restoring the data from /proc/mymsg and reporting it again.

 

Based on the touch screen driver (input subsystem) experiment, perform the following command test:

 

export TSLIB_TSDEVICE=/dev/event0

export TSLIB_CALIBFILE=/etc/pointercal

export TSLIB_CONFFILE=/etc/ts.conf

export TSLIB_PLUGINDIR=/lib/ts

export TSLIB_CONSOLEDEVICE=none

export TSLIB_FBDEVICE=/dev/fb0

 

insmod mymsg.ko //Load the myprintk driver you wrote

insmod touch_emulate.ko //touch screen driver

./emulate_test tag 100ask //Add a tag to the touch data saved in the mymsg file

cat /proc/mymsg //View the contents of mymsg file

ts_test //Test touch screen command. This command will only be effective after the touch screen driver is loaded.

Random line drawing

cp /proc/mymsg /ts2.txt //After the copy is complete, press ctrl+c to exit

sudo chmod 777 ts.txt //Execute the command on the server

./emulate_test write /ts.txt

ts_test & //Use the ps command to view the running ts_test process. You can use: kill -9 + process number, command to kill the process

./emulate_test replay

 

 

Note: When the program fails to execute the replay_get_line(line); function to obtain a line of data, it always returns that the data exists, so the del_timer(&replay_timer); function cannot be executed. When the driver is unloaded and a new driver is reloaded, the old timer variable still exists. When add_timer(&replay_timer); is executed, the system will report the following error. Only a system reset can solve the problem.

kernel BUG at include/linux/timer.h:153!

Unable to handle kernel NULL pointer dereference at vi rtu al address 0000000 pgd=c3f50000


Keywords:ARM Reference address:ARM embedded application debugging input simulator writing test simulation function

Previous article:STM32 writes fonts to external FLASH (W25X16) through the serial port
Next article:ARM embedded LCD driver display picture

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号