-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First version of a live mutual capacitance visualizer
- Loading branch information
Showing
7 changed files
with
821 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.o | ||
CapacitanceVisualizer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
Oops, something went wrong.