Month: February 2010

Emulating a read-only serial

This is a read only serial driver which I developed to emulate a real GPS.
Here you will find just the stub of original driver, anyway it should work correctly.
When you execute “cat /dev/ttytest0” you should see “Just a simple serial test” string.

/****************************************************************************/
/*
 *	test.c
 *
 *	(C) Copyright 2010, Alan Carvalho de Assis 
 *
 * 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.
 */

/****************************************************************************/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/workqueue.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
//#include 

static int debug = 1;

#define dbg(fmt, arg...)						\
	do {								\
		if (debug)						\
			printk (KERN_DEBUG "%s: %s: " fmt "\n",		\
				"test" , __FUNCTION__ , ## arg);	\
	} while (0)

#define TEST_INTERVAL 100

static void test_callback(struct work_struct *ignored);
static struct delayed_work test_work;

struct uart_port *myport;

/****************************************************************************/

char mystring[] = "Just a simple serial test\n";

/****************************************************************************/

/*
 *	Local per-uart structure.
 */
struct test_uart {
	struct uart_port	port;
	unsigned int		sigs;		/* Local copy of line sigs */
	unsigned char		imr;		/* Local IMR mirror */
};

/****************************************************************************/

static unsigned int test_tx_empty(struct uart_port *port)
{
	dbg();

	return 0;
}

/****************************************************************************/

static unsigned int test_get_mctrl(struct uart_port *port)
{
	dbg();

	return 0;
}

/****************************************************************************/

static void test_set_mctrl(struct uart_port *port, unsigned int sigs)
{
	dbg();
}

/****************************************************************************/

static void test_tx_chars(struct test_uart *pp)
{
	dbg();
}

/****************************************************************************/

static void test_start_tx(struct uart_port *port)
{
	dbg();

	test_tx_chars(NULL);
}

/****************************************************************************/

static void test_stop_tx(struct uart_port *port)
{
	dbg();
}

/****************************************************************************/

static void test_stop_rx(struct uart_port *port)
{
	dbg();
}

/****************************************************************************/

static void test_break_ctl(struct uart_port *port, int break_state)
{
	dbg();
}

/****************************************************************************/

static void test_enable_ms(struct uart_port *port)
{
	dbg();
}

/****************************************************************************/

static int test_startup(struct uart_port *port)
{
	dbg();

	/* schedule a delayed work to start receiving data */
	INIT_DELAYED_WORK(&test_work, test_callback);
	schedule_delayed_work(&test_work, TEST_INTERVAL);

	return 0;
}

/****************************************************************************/

static void test_shutdown(struct uart_port *port)
{
	dbg();

	cancel_delayed_work(&test_work);
}

/****************************************************************************/

static void test_set_termios(struct uart_port *port, struct ktermios *termios,
	struct ktermios *old)
{
	dbg();
}

/****************************************************************************/

static void test_rx_chars(struct test_uart *pp)
{
	unsigned char ch, flag;
	int len, i = 0;

	dbg();

	len = strlen(mystring) + 1;

	while (i < len) {
		ch = mystring[i++];
		flag = TTY_NORMAL;

		tty_insert_flip_char(myport->state->port.tty, ch, flag);
	}

	tty_flip_buffer_push(myport->state->port.tty);
}

/****************************************************************************/

static void test_callback(struct work_struct *ignored)
{
	//struct test_uart *pp = container_of(myport, struct test_uart, port);

	dbg();

	/* receive characters and send it to user */
	test_rx_chars(NULL);

	/* call me again */
	schedule_delayed_work(&test_work, TEST_INTERVAL);
}

/****************************************************************************/

static void test_config_port(struct uart_port *port, int flags)
{
	dbg();
}

/****************************************************************************/

static const char *test_type(struct uart_port *port)
{
	dbg();
	return (port->type == PORT_test) ? "Maxtrack UART" : NULL;
}

/****************************************************************************/

static int test_request_port(struct uart_port *port)
{
	dbg();

	/* UARTs always present */
	return 0;
}

/****************************************************************************/

static void test_release_port(struct uart_port *port)
{
	dbg();

	/* Nothing to release... */
}

/****************************************************************************/

static int test_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	dbg();

	if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_test))
		return -EINVAL;
	return 0;
}

/****************************************************************************/

/*
 *	Define the basic serial functions we support.
 */
static struct uart_ops test_uart_ops = {
	.tx_empty	= test_tx_empty,
	.get_mctrl	= test_get_mctrl,
	.set_mctrl	= test_set_mctrl,
	.start_tx	= test_start_tx,
	.stop_tx	= test_stop_tx,
	.stop_rx	= test_stop_rx,
	.enable_ms	= test_enable_ms,
	.break_ctl	= test_break_ctl,
	.startup	= test_startup,
	.shutdown	= test_shutdown,
	.set_termios	= test_set_termios,
	.type		= test_type,
	.request_port	= test_request_port,
	.release_port	= test_release_port,
	.config_port	= test_config_port,
	.verify_port	= test_verify_port,
};

static struct test_uart test_ports[1];

/****************************************************************************/

/*
 *	Define the test UART driver structure.
 */
static struct uart_driver test_driver = {
	.owner		= THIS_MODULE,
	.driver_name	= "test",
	.dev_name	= "ttytest",
	.nr		= 1,
};

/****************************************************************************/

static int test_remove(struct platform_device *pdev)
{
	struct uart_port *port;

	port = &test_ports[0].port;
	if (port)
		uart_remove_one_port(&test_driver, port);

	return 0;
}

/****************************************************************************/

static int __init test_init(void)
{
	int rc;

	struct uart_port *port;

	rc = uart_register_driver(&test_driver);
	if (rc)
		return rc;

	port = &test_ports[0].port;

	port->line = 0;
	port->type = PORT_TEST; /*remember to define PORT_TEST at include/linux/serial_core.h */
	port->iotype = SERIAL_IO_MEM;
	port->ops = &test_uart_ops;
	port->flags = ASYNC_BOOT_AUTOCONF;

	uart_add_one_port(&test_driver, port);

	myport = port;

	return 0;
}

/****************************************************************************/

static void __exit test_exit(void)
{
	cancel_delayed_work(&test_work);

	uart_unregister_driver(&test_driver);
}

/****************************************************************************/

module_init(test_init);
module_exit(test_exit);

MODULE_AUTHOR("Alan Carvalho de Assis ");
MODULE_DESCRIPTION("Test UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:testuart");
/****************************************************************************/

Creating a counter using other way

Recently I created a simple board to test the HCS08 chip used on my wash machine, it is a very simple board with just the microcontroller and two LEDs (wired to PTE1 and PTE3).

Then I created a simple binary counter program to test it:

#define LED1 PTED_PTED1
#define LED2 PTED_PTED3

void main(void)
{
    int i = 0;
    MCU_init();
    PTEDD = 0x0F;
    LED1 = 0;
    LED2 = 0;
    while(1){
        i++;
        LED1 = i & 1;
        LED2 = (i & 2) >> 1;
        mdelay(500);
    }
}

It worked fine, but then I started to thing another way to count without using a counter (i++).
I realized the LED1 (bit 0) always goes some sequence (0->1->0->1…), it could be done easily using a Exclusive OR (XOR) logic: LED1 = LED1 ^ 1 or Not Logic: LED1 = ~LED1;
Also I noticed which LED2 (bit 1) only turns ON or OFF after a LED1 transition from 1 to 0. Then I could create a variable T (Temporary) to save previous LED1 state and compare it with current status. Case previous state is 1 and current status is 0 it should inverts the LED2 state, then just do that: LED2 = LED2 ^ (T & ~LED1), then I got it:

#define LED1 PTED_PTED1
#define LED2 PTED_PTED3

void main(void)
{
    int i = 0, T = 0;
    MCU_init();
    PTEDD = 0x0F;
    LED1 = 0;
    LED2 = 0;
    while(1){
        LED1 = LED1 ^ 1;
        LED2 = LED2 ^ (T & ~LED1);
        T = LED1;
        mdelay(500);
    }
}

It worked, but just after doing this way I realized my mistake: I don’t need to compare previous state, because LED1 just was 1 before it turns 0 (except the first time, but it doesn’t matter), then the above code could be reduced to:

#define LED1 PTED_PTED1
#define LED2 PTED_PTED3

void main(void)
{
    MCU_init();
    PTEDD = 0x0F;
    LED1 = 0;
    LED2 = 0;
    while(1){
        LED1 = LED1 ^ 1;
        LED2 = LED2 ^ ~LED1;
        mdelay(500);
    }
}

It fact I created a counter without using an ADD instruction. To be honest I never saw a microcontroller without ADD instruction, but if some day I got one I could do a counter easily 😉

Symbian open-sourced too late

Today my cell phone alarm didn’t work, it is strange because the alarm application used on Qtopia has two times to wake me up (6:30 AM and 7:00AM). Fortunately I woken up on time (7:05 AM) because the cars traffic noises near my home. 🙂

What is the relation between this first paragraph and the Symbian OS? Well, Symbian cell phone (mainly Nokia) are very reliable and normally you will wake up on time.

Besides Symbian reliability it is losing market share. Why? Mainly because Symbian is not fine tunned to use on Smartphones and doesn’t have nice features as Android and iPhone OS.

This week Nokia announced it has finally opened Symbian source code. It was a good news, but in fact it is not a great news, nobody started to sing-and-dance because this “Nokan-move”.