Skip to content

Commit

Permalink
First version of a live mutual capacitance visualizer
Browse files Browse the repository at this point in the history
  • Loading branch information
optisimon committed Jul 15, 2016
1 parent 5f8d81d commit bb7ec4c
Show file tree
Hide file tree
Showing 7 changed files with 821 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CapacitanceVisualizer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.o
CapacitanceVisualizer
185 changes: 185 additions & 0 deletions CapacitanceVisualizer/FT5406.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* FT5406.hpp
*
* Created on: Jul 15, 2016
*
* Copyright (c) 2016 Simon Gustafsson (www.optisimon.com)
* Do whatever you like with this code, but please refer to me as the original author.
*/


#pragma once

#include "Image.hpp"

#include <stdexcept>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>


class FT5406 {
public:
enum { NUM_ROWS = 22 };
enum { NUM_COLUMNS = 12 };

FT5406(int adapter_nr, int addr = 0x38, bool verbose = false) : _fd(0), _testMode(false), _verbose(verbose)
{
char fname[20];
snprintf(fname, sizeof(fname)-1, "/dev/i2c-%d", adapter_nr);

_fd = open(fname, O_RDWR);

if (_fd < 0)
{
throw std::runtime_error("Unable to open requested I2C device");
}

if (ioctl(_fd, I2C_SLAVE, addr) < 0)
{
throw std::runtime_error("Unable to select i2c slave address");
}
}


void setTestMode()
{
int status = i2c_smbus_write_byte_data(_fd, 0x00, 0x40);

if (status < 0)
{
throw std::runtime_error("i2c write failed");
}
_testMode = true;
}


void refreshSensor()
{
// We require testMode to be set
ensureTestMode();

// Start new scan of touch screen
startNewSensorScan();

// Wait for scan to complete
waitForScanCompletion();
}

Image readImage()
{
assert(_testMode);

int rows = NUM_ROWS;
int cols = NUM_COLUMNS;

Image retval(cols, rows);
retval.data.clear();

for (int rowAddr = 0; rowAddr < rows; rowAddr++)
{
int status = i2c_smbus_write_byte_data(_fd, 0x01, rowAddr);
if (status < 0)
{
throw std::runtime_error("i2c write failed");
}

usleep(100); // Wait at least 100us

#if 0
// sample this row
for (int col = 0; col < cols; col++)
{
int val = i2c_smbus_read_word_data(_fd, 16 + (2 * col));
if (val == -1)
{
throw std::runtime_error("i2c read error");
}
val = ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
retval.data.push_back(val);
}
#else
// TODO: This won't work for kernel < 2.6.23. Should I care?
uint8_t values[2*cols];
status = i2c_smbus_read_i2c_block_data(_fd, 16, 2*cols, values);
if (status != 2*cols)
{
throw std::runtime_error("i2c read error");
}

for (int col = 0; col < cols; col++)
{
int val = (values[2 * col] << 8) | (values[2 * col + 1]);
retval.data.push_back(val);

if (_verbose)
{
printf("0x%04x ", val);
}
}
#endif
if (_verbose)
{
printf("\n");
}
}
if (_verbose)
{
printf("\n");
}
return retval;
}

private:
void ensureTestMode()
{
if (!_testMode)
{
setTestMode();
}
}

/** Assumes we already are in test mode */
void startNewSensorScan()
{
int ret = i2c_smbus_write_byte_data(_fd, 0x00, 0xc0);
if (ret < 0)
{
throw std::runtime_error("i2c write failed");
}
}

/** Blocks until sensor scan is completed */
void waitForScanCompletion()
{
while (true)
{
int ret = i2c_smbus_read_byte_data(_fd, 0x00);

if (ret < 0)
{
throw std::runtime_error("i2c read failed");
}
else if (ret == 0x40)
{
return;
}
else
{
if (_verbose)
{
printf("Got 0x%02x - waiting longer\n", ret);
}
usleep(3000); // without this, we usually wait something like 17 full i2c transactions.
}
}
}

int _fd;
bool _testMode;
const bool _verbose;
};
39 changes: 39 additions & 0 deletions CapacitanceVisualizer/Image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Image.hpp
*
* Created on: Jul 15, 2016
*
* Copyright (c) 2016 Simon Gustafsson (www.optisimon.com)
* Do whatever you like with this code, but please refer to me as the original author.
*/

#pragma once

#include <vector>

struct Image {
int w;
int h;
std::vector<int> data;

Image(int w, int h) : w(w), h(h)
{
data.resize(w*h, 0);
}

/** Flip image along its diagonal*/
Image getTransposed() const
{
Image i(h, w);
i.data.clear();

for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
i.data.push_back(data[y * w + x]);
}
}
return i;
}
};
36 changes: 36 additions & 0 deletions CapacitanceVisualizer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
DESTDIR?=""

INCLUDE= `sdl-config --cflags`
LIBS= `sdl-config --libs` -lSDL_gfx -lpthread

CapacitanceVisualizer_OBJS= main.o
CapacitanceVisualizer_LIBS= $(LIBS)

EXECS= CapacitanceVisualizer
EXEC_installed= CapacitanceVisualizer

COMPILER_FLAGS+= -Wall -O3 -std=c++0x -ggdb

CapacitanceVisualizer: $(CapacitanceVisualizer_OBJS) $(wildcard *.h) $(wildcard *.hpp) Makefile
$(CXX) $(COMPILER_FLAGS) -o $@ $($@_OBJS) $($@_LIBS)

%.o: %.cpp
$(CXX) -c $(COMPILER_FLAGS) -o $@ $< $(INCLUDE)

all : CapacitanceVisualizer

.PHONY: install
install: $(EXEC_installed)
install $(EXEC_installed) $(DESTDIR)/usr/local/bin

.PHONY: uninstall
uninstall:
rm $(DESTDIR)/usr/local/bin/$(EXEC_installed)

.PHONY: prepare
prepare:
apt-get install libsdl1.2-dev libsdl-gfx1.2-dev libi2c-dev

.PHONY: clean
clean:
rm -f $(EXECS) $(CapacitanceVisualizer_OBJS)
106 changes: 106 additions & 0 deletions CapacitanceVisualizer/SDLEventHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* SDLEventHandler.hpp
*
* Created on: Jun 19, 2016
*
* Copyright (c) 2016 Simon Gustafsson (www.optisimon.com)
* Do whatever you like with this code, but please refer to me as the original author.
*/

#pragma once

#include <SDL/SDL.h>


class SDLEventHandler {
public:
SDLEventHandler() :
_should_quit(false),
_should_go_fullscreen(false),
_should_sample_background(false),
_zoom(1)
{
refresh();
}

void refresh()
{
SDL_Event event;

while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_QUIT )
{
_should_quit = true;
}

if ( event.type == SDL_KEYDOWN )
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
_should_quit = true;
break;

case SDLK_F1:
_should_sample_background ^= true;
break;

case SDLK_F11:
_should_go_fullscreen ^= true;
break;

case SDLK_KP_PLUS:
case SDLK_PLUS:
_zoom = std::min<int>(40, _zoom + 1);
break;

case SDLK_KP_MINUS:
case SDLK_MINUS:
_zoom = std::max<int>(1, _zoom - 1);
break;

case SDLK_SPACE:
break;
default:
break;
}
}

if (event.type == SDL_MOUSEBUTTONDOWN)
{
if(event.button.button == 1 &&
event.button.state == SDL_PRESSED)
{
_should_go_fullscreen ^= true;
}
}

if (event.type == SDL_VIDEORESIZE)
{
int w = event.resize.w;
int h = event.resize.h;
std::cout
<< "Resize events not supported. (resize to "
<< w << "x" << h << " requested)\n";
}
}
}

bool shouldQuit() const { return _should_quit; }

bool shouldGoFullscreen() const { return _should_go_fullscreen; }

bool shouldSampleBackground() const { return _should_sample_background; }
void clearShouldSampleBackground() { _should_sample_background = false; }

void setZoom(int val) { _zoom = val; }
int getZoom() const { return _zoom; }


private:
bool _should_quit;
bool _should_go_fullscreen;
bool _should_sample_background;
int _zoom;
};
Loading

0 comments on commit bb7ec4c

Please sign in to comment.