pmeerw's blog

Tweets

Sun, 26 Jan 2014

Watching for new files on Linux

Linux has a relatively new (2.6.13, June 2005), easy-to-use interface to watch and monitor file operation: inotify. See the Linux Journal article also.

I plan to use it to see when new devices show up under /dev:

#include 

static const char *progname = "ino";

static const char *inotify_mask_str(unsigned mask) {
    switch (mask) {
    case IN_CREATE: return "create";
    case IN_DELETE: return "delete";
    default: return "???";
    }
}

int main() {
    int fd = inotify_init1(0);
    if (fd < 0) {
        fprintf(stderr, "%s: init failed\n", progname);
        exit(EXIT_FAILURE);
    }

    int wd = inotify_add_watch(fd, "/dev", IN_CREATE | IN_DELETE);
    if (wd < 0) {
        fprintf(stderr, "%s: add watch failed\n", progname);
        exit(EXIT_FAILURE);
    }

    while (true) {
       uint8_t buf[sizeof(struct inotify_event) + FILENAME_MAX + 1];
       ssize_t ret = read(fd, &buf, sizeof(buf));
       if (ret < 0) {
           if (errno == EINTR) continue;
           fprintf(stderr, "%s: read failed\n", progname);
           exit(EXIT_FAILURE);
       }
       
       size_t processed = 0;
       while (processed < ret - sizeof(struct inotify_event)) {
           struct inotify_event *iev = (struct inotify_event *) &buf[processed];
           printf("%4zd:%08x %s %s\n", ret,
               iev->mask, inotify_mask_str(iev->mask), iev->name);
           processed += sizeof(struct inotify_event) + iev->len;
       }
   }
   
   close(wd);
   close(fd);
   
   return EXIT_SUCCESS;
}

posted at: 15:31 | path: /programming | permanent link | 0 comments

Encoding UYVY data to JPEG efficiently

Encoding image data to JPEG is straightforward: use libjpeg. However, if you care about runtime performance, things get a bit more complicated... Here are some observations on the task on a ARM Cortex-A8 CPU.

  1. There is libjpeg-turbo which is a drop-in replacement for libjpeg and offers SIMD (in our case ARM NEON) support.
  2. Use dct_method = JDCT_IFAST.
    # time ./cjpeg -dct int -q 70 test.ppm > /tmp/test.jpg
    real	0m 1.70s
    # time ./cjpeg -dct fast -q 70 test.ppm > /tmp/test.jpg
    real	0m 1.04s
    
  3. Avoid color-space conversion: JPEG uses YUV internally, RGB input is converted to YUV before compression. Use in_color_space = JCS_YCbCr to avoid extra effort.
  4. Avoid downsampling. UYVY data has only half the chroma resolution in horizontal direction. JPEG usually does chroma subsampling in both directions. The libjpeg interface cannot handle irregular input data unless raw_data_in = TRUE is used. The raw interface requires rearranging input data, however.
  5. Prepare input buffers efficiently, compiler settings matter (-O2).

struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);

jpeg_create_compress(&cinfo);
cinfo.image_width = w;
cinfo.image_height = h;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_YCbCr; // input color space

jpeg_mem_dest(&cinfo, &outbuf, outbuf_size);
jpeg_set_defaults(&cinfo);
cinfo.dct_method = JDCT_IFAST; // DCT method

// set up subsampling
cinfo.raw_data_in = TRUE;
cinfo.comp_info[0].h_samp_factor = 2;
cinfo.comp_info[0].v_samp_factor = 2;
cinfo.comp_info[1].h_samp_factor = 1;
cinfo.comp_info[1].v_samp_factor = 1;
cinfo.comp_info[2].h_samp_factor = 1;
cinfo.comp_info[2].v_samp_factor = 1;                                                

jpeg_set_quality(&cinfo, 70, TRUE);
jpeg_start_compress(&cinfo, TRUE);

// allocate input data buffer
JSAMPIMAGE data = malloc(sizeof(JSAMPARRAY) * cinfo.input_components);
data[0] = malloc(sizeof(JSAMPROW) * (16 + 8 + 8));
data[1] = data[0] + 16;
data[2] = data[0] + 16 + 8;

// Y component
data[0][0] = malloc(sizeof(JSAMPLE) * cinfo.image_width * 16);
for (unsigned i = 1; i < 16; i++)
  data[0][i] = data[0][i-1] + cinfo.image_width;

// U component
data[1][0] = malloc(sizeof(JSAMPLE) * cinfo.image_width * 8 / 2);
for (unsigned i = 1; i < 8; i++)
  data[1][i] = data[1][i-1] + cinfo.image_width / 2;
  
// V component
data[2][0] = malloc(sizeof(JSAMPLE) * cinfo.image_width * 8 / 2);
for (unsigned i = 1; i < 8; i++)
  data[2][i] = data[2][i-1] + cinfo.image_width / 2;

JSAMPLE *in = inbuf;
for (unsigned i = 0; i < cinfo.image_height; i += 16) {
  JSAMPLE *yp = data[0][0], *up = data[1][0], *vp = data[2][0];
  for (unsigned j = 0; j < 16; j += 2) {
    for (unsigned k = 0; k < cinfo.image_width * 2; k += 4) {
      *up++ = *in++; // assume UYVY
      *yp++ = *in++;
      *vp++ = *in++;
      *yp++ = *in++;
    }
    for (unsigned k = 0; k < cinfo.image_width * 2; k += 4) {
      in++; // subsample by dropping chroma data on odd lines
      *yp++ = *in++;
      in++;
      *yp++ = *in++;
    }
  }
  jpeg_write_raw_data(&cinfo, data, 16);
}
  
free(data[0][0]);
free(data[1][0]);
free(data[2][0]);
free(data[0]);
free(data);

jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);

posted at: 15:19 | path: /programming | permanent link | 0 comments

Thu, 09 Jan 2014

Olimex lime board

I got one of the first Olimex lime boards (Allwinner A10 Cortex-A8 CPU, 1GHz with Mali 400 GPU, 512 MB RAM, SATA, HDMI, 2x USB host, 100 MBit Ethernet). It comes with a nice case. Don't forget to order a 40-pin 0.05" step cable to access the GPIO / LCD connector banks. Unfortunately, the UART / serial pins are not led out of the case. As always, a 5V DC power supply and FTDI TTL-232R3v3 cable come in handy.

The /proc/cpuinfo is not that spectacular:

Processor       : ARMv7 Processor rev 2 (v7l)
BogoMIPS        : 405.52
Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x3
CPU part        : 0xc08
CPU revision    : 2

Hardware        : sun4i
Revision        : 0000
Serial          : 0000000000000000
Some benchmark results are available here.

Guide to compile kernel and u-boot is here.
Information on linux-sunxi.

posted at: 17:51 | path: /projects | permanent link | 0 comments

Thu, 17 Oct 2013

Acer Aspire E1-572 and Linux

Setting up a brand-new Acer Aspire E1-572 laptop computer with Linux Ubuntu 13.10 "saucy". The machine came without Windows. Specs: Intel i5-4200U, 15.6" Full HD (1920x1080 pixels) matte display, 500 GB HD, 4 GB RAM, DVD-RW driver, 4-cell battery, USB 3.0, Wireless 802.11n, Bluetooth, HDMI.

What works out-of-the-box:

This does not work (yet): Not tried (yet):

Here is some output:

processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 69
model name	: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
stepping	: 1
microcode	: 0x10
cpu MHz		: 759.000
cache size	: 3072 KB
physical id	: 0
siblings	: 4
core id		: 0
cpu cores	: 2
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid
bogomips	: 4589.70
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:
$ lspci
00:00.0 Host bridge: Intel Corporation Haswell-ULT DRAM Controller (rev 09)
00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 09)
00:03.0 Audio device: Intel Corporation Device 0a0c (rev 09)
00:14.0 USB controller: Intel Corporation Lynx Point-LP USB xHCI HC (rev 04)
00:16.0 Communication controller: Intel Corporation Lynx Point-LP HECI #0 (rev 04)
00:1b.0 Audio device: Intel Corporation Lynx Point-LP HD Audio Controller (rev 04)
00:1c.0 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root Port 3 (rev e4)
00:1c.3 PCI bridge: Intel Corporation Lynx Point-LP PCI Express Root Port 4 (rev e4)
00:1d.0 USB controller: Intel Corporation Lynx Point-LP USB EHCI #1 (rev 04)
00:1f.0 ISA bridge: Intel Corporation Lynx Point-LP LPC Controller (rev 04)
00:1f.2 SATA controller: Intel Corporation Lynx Point-LP SATA Controller 1 [AHCI mode] (rev 04)
00:1f.3 SMBus: Intel Corporation Lynx Point-LP SMBus Controller (rev 04)
01:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM57786 Gigabit Ethernet PCIe (rev 01)
01:00.1 SD Host controller: Broadcom Corporation BCM57765/57785 SDXC/MMC Card Reader (rev 01)
02:00.0 Network controller: Qualcomm Atheros QCA9565 / AR9565 Wireless Network Adapter (rev 01)
$ lsusb
Bus 001 Device 002: ID 8087:8000 Intel Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 005: ID 1bcf:2c17 Sunplus Innovation Technology Inc. 
Bus 002 Device 004: ID 04ca:300b Lite-On Technology Corp. 
Bus 002 Device 002: ID 046d:c050 Logitech, Inc. RX 250 Optical Mouse
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

posted at: 23:05 | path: /review | permanent link | 0 comments

Sun, 15 Sep 2013

Radio repair man!

Fixed a cheap Elta radio with alarm clock by resordering several solder points. It was hard to find a reasonable replacement (without a gadget dock).

posted at: 16:39 | path: /projects | permanent link | 0 comments

Sun, 07 Jul 2013

NFC experiment

Hooked up an Adafruit PN532 breakout via FTDI serial cable.

Of course it did not work. Some patches later:

pmeerw@sirene:~/src/nfc/libnfc$ utils/nfc-scan-device -v
nfc-scan-device uses libnfc libnfc-1.7.0-rc7-45-gede5ebd
1 NFC device(s) found:
- pn532_uart:/dev/ttyUSB1:
    pn532_uart:/dev/ttyUSB1
chip: PN532 v1.6
initator mode modulations: ISO/IEC 14443A (106 kbps), FeliCa (424 kbps, 212 kbps), ISO/IEC 14443-4B (106 kbps), Innovision Jewel (106 kbps), D.E.P. (424 kbps, 212 kbps, 106 kbps)
target mode modulations: ISO/IEC 14443A (106 kbps), FeliCa (424 kbps, 212 kbps), D.E.P. (424 kbps, 212 kbps, 106 kbps)
pmeerw@sirene:~/src/nfc/libnfc$ examples/nfc-poll -v
nfc-poll uses libnfc libnfc-1.7.0-rc7-45-gede5ebd
NFC reader: pn532_uart:/dev/ttyUSB1 opened
NFC device will poll during 30000 ms (20 pollings of 300 ms for 5 modulations)
ISO/IEC 14443A (106 kbps) target:
    ATQA (SENS_RES): 00  04  
* UID size: single
* bit frame anticollision supported
       UID (NFCID1): xx  xx  xx  xx  
      SAK (SEL_RES): 08  
* Not compliant with ISO/IEC 14443-4
* Not compliant with ISO/IEC 18092
                       
Fingerprinting based on MIFARE type Identification Procedure:
* MIFARE Classic 1K
* MIFARE Plus (4 Byte UID or 4 Byte RID) 2K, Security level 1
* SmartMX with MIFARE 1K emulation
Other possible matches based on ATQA & SAK values:

Make sure to edit /usr/local/etc/nfs/libnfc.conf:

device.name = "microBuilder.eu"
device.connstring = "pn532_uart:/dev/ttyUSB1"

posted at: 00:18 | path: /projects | permanent link | 0 comments

Fri, 31 May 2013

I2C device (TAOS TSL45315 ALS) test with Bus Pirate

Bus Pirate is a USB device that connects to a variety of digital electronic components (e.g. EEPROMs, sensors) via protocols such as I2C, SPI, UART, 1-wire. Towards the host-side it offers a serial terminal with a single text interface, so no software to install.

So I want to hook up a TAOS TSL45315 ambient light sensor (ALS) via I2c. The most difficult part is to find the right cables of the Bus Pirate for the SDA, CLK, GND and 3v3 signals.

Then fire up a terminal (minicom -D /dev/ttyUSBx) and you'll see the Bus Pirate prompt: HiZ>. Help is available with ?. Typing m 4 3 changes to I2C mode, W turns on the power supply output, P enables pullups.

Entering (1) runs a macro which scans the I2C bus for devices; here a chip with 7-bit address 0x29 shows up (yeah, this is our TSL45315 -- check the datasheet!):

I2C>(1)
Searching I2C address space. Found devices at:
0x52(0x29 W) 0x53(0x29 R) 

To turn on the sensor and make a measurement:

I2C>[0x52 0x80 0x03]
I2C START BIT
WRITE: 0x52 ACK 
WRITE: 0x80 ACK 
WRITE: 0x03 ACK 
I2C STOP BIT

I2C>[0x52 0x84 [ 0x53 rr ]
I2C START BIT
WRITE: 0x52 ACK 
WRITE: 0x84 ACK 
I2C START BIT
WRITE: 0x53 ACK 
READ: 0xC6 
READ:  ACK 0x00 
NACK
I2C STOP BIT
The first command ([0x52 0x80 0x03]) addresses the chip for writing (0x52) and sets the value 0x03 to register 0x00 (the MSB has to be set). The second command ([0x52 0x84 [ 0x53 rr ]) selects the data low register (0x04, MSB set, hence 0x84) and then instructs the chip to read two bytes. The results is 0xc6, 0x00 which gives the ambient light in lux: (0x00 << 8) | 0xc6.

posted at: 11:44 | path: /projects | permanent link | 0 comments

Made with PyBlosxom