Write OLED driver for RaspberryPi - linux-kernel

I am writing a driver module for my 128x64 OLED(ssd1306), which will be used on my raspberry pi. And it works in 4-wire SPI mode. Firstly, I read the datasheet of the ssd1306 and wrote some basic functions. Then I connected this OLED with an Arduino board, ran the codes to test its correctness and I found it worked quite well.
Here are my arduino code:
//oled.ino
#define clearPin(a) digitalWrite(a, LOW)
#define setPin(a) digitalWrite(a, HIGH)
char* hello = "Hello World!";
// visible ascii chars
const unsigned char F6x8[][6] =
{
//...
};
const unsigned char F8X16[]=
{
//...
};
// pin assignments
int CS = 53;
int DIN = 51;
int CLK = 52;
int DC = 3;
int RES = 2;
//***********************************
int writeCommand(byte command)
{
int i;
clearPin(CS);
clearPin(DC);
for(i = 0; i < 8; i++)
{
clearPin(CLK);
delay(1);
if((command >> (7-i)) & 0x1)
setPin(DIN);
else
clearPin(DIN);
delay(1);
setPin(CLK);
delay(1);
}
setPin(CS);
}
int writeData(byte data)
{
int i;
clearPin(CS);
setPin(DC);
for(i = 0; i < 8; i++)
{
clearPin(CLK);
delay(1);
if((data >> (7 - i)) & 0x1)
setPin(DIN);
else
clearPin(DIN);
delay(1);
setPin(CLK);
delay(1);
}
setPin(CS);
}
void setPostion(byte x, byte y)
{
writeCommand(0xB0 | y); // go to page y
writeCommand(0x00 | (x & 0x0f)); // setPin lower column address
writeCommand(0x10 | ((x >> 4) & 0x0f)); // setPin higher column address
}
void write6x8Char(byte x, byte y, char ch)
{
setPostion(x, y);
int i, c = ch - 32;
for(i = 0; i < 6; i++)
writeData(F6x8[c][i]);
}
void write6x8String(byte x, byte y, char* str)
{
//...
}
void write8x16Char(byte x, byte y, char ch)
{
setPostion(x, y);
int i, c = ch - 32;
for(i = 0; i < 8; i++)
writeData(F8X16[c * 16 + i]);
setPostion(x, y+1);
for(i = 8; i < 16; i++)
writeData(F8X16[c * 16 + i]);
}
void write8x16String(byte x, byte y, char* str)
{
//...
}
void clearScreen()
{
fill(0);
}
void fill(unsigned char bmp_data)
{
unsigned char y,x;
for(y = 0; y < 8; y++)
{
writeCommand(0xb0 + y);
writeCommand(0x00);
writeCommand(0x10);
for(x = 0; x < 128; x++)
writeData(bmp_data);
}
}
void setDisplayOn(byte on)
{
writeCommand(0xAE | on);
}
//***********************************************
void initialize()
{
setPin(CLK);
clearPin(RES);
delay(50);
setPin(RES);
setDisplayOn(1);
fill(0x00);
}
void setup()
{
pinMode(CS, OUTPUT);
pinMode(DIN, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(DC, OUTPUT);
pinMode(RES, OUTPUT);
initialize();
}
void loop()
{
write8x16String(0, 0, hello);
}
So I moved them directly into my driver module file with few necessary changes. Here are my oled.c file and Makefile:
//oled.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define DRIVER_NAME "OLED"
#define DEVICE_NAME "OLED"
#define clearGPIO(a) gpio_set_value(a, 0)
#define setGPIO(a) gpio_set_value(a, 1)
const int DIN = 5;
const int CLK = 6;
const int CS = 13;
const int DC = 19;
const int RES = 26;
const unsigned char F6x8[][6] =
{
//...
};
const unsigned char F8X16[]=
{
//...
};
//*****************************************
void delay(int ms)
{
int i, j;
for(i = 0; i < ms; i++)
{
j = 100000;
while(j--);
}
}
//...Same functions with the arduino program...
//*****************************************
static dev_t oled_devno;
static struct class *oled_class;
static struct cdev oled_dev;
static int flag = 0;
//open
static int oled_open(struct inode *inode, struct file *filp)
{
int err;
printk(KERN_INFO"Initializing GPIOs...\n");
err = gpio_request_one(CS, GPIOF_OUT_INIT_LOW, "CS");
if(err){
printk(KERN_ERR"[%s %d]:Request led gpio failed\n", __func__, __LINE__);
gpio_free(CS);
}
err = gpio_request_one(DC, GPIOF_OUT_INIT_LOW, "DC");
if(err){
printk(KERN_ERR"[%s %d]:Request led gpio failed\n", __func__, __LINE__);
gpio_free(DC);
}
err = gpio_request_one(RES, GPIOF_OUT_INIT_LOW, "RES");
if(err){
printk(KERN_ERR"[%s %d]:Request led gpio failed\n", __func__, __LINE__);
gpio_free(RES);
}
err = gpio_request_one(DIN, GPIOF_OUT_INIT_LOW, "DIN");
if(err){
printk(KERN_ERR"[%s %d]:Request led gpio failed\n", __func__, __LINE__);
gpio_free(DIN);
}
err = gpio_request_one(CLK, GPIOF_OUT_INIT_LOW, "CLK");
if(err){
printk(KERN_ERR"[%s %d]:Request led gpio failed\n", __func__, __LINE__);
gpio_free(CLK);
}
flag = 1;
printk(KERN_INFO"Initializing OLED...\n");
oled_initialize();
printk(KERN_INFO"OLED open\n");
return 0;
}
//release
static int oled_release(struct inode *inode, struct file *filp)
{
if(flag)
{
gpio_free(CS);
gpio_free(DC);
gpio_free(RES);
gpio_free(DIN);
gpio_free(CLK);
}
printk(KERN_INFO"OLED release\n");
return 0;
}
//write
ssize_t oled_write(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
char* hello = "Hello driver";
printk(KERN_INFO"I am writing data!\n");
write8x16String(0, 0, hello);
return 0;
}
static struct file_operations oled_fops = {
.owner = THIS_MODULE,
.open = oled_open,
.release = oled_release,
.write = oled_write,
};
static int __init oled_init(void)
{
int err;
printk(KERN_INFO"OLED Init \n");
err = alloc_chrdev_region(&oled_devno,0,1,DRIVER_NAME);
if(err < 0){
goto err;
}
cdev_init(&oled_dev,&oled_fops);
err = cdev_add(&oled_dev,oled_devno,1);
if(err < 0)
{
printk(KERN_ERR"[%s,%d]add cdev failed\n",__func__,__LINE__);
goto FREE_DEVNO;
}
//
oled_class = class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(oled_class))
{
printk(KERN_ERR"[%s,%d]class create failed\n",__func__,__LINE__);
goto DEV_FREE;
}
device_create(oled_class,NULL,oled_devno,NULL,DEVICE_NAME);
return 0;
DEV_FREE:
cdev_del(&oled_dev);
FREE_DEVNO:
unregister_chrdev_region(oled_devno, 1);
err:
return err;
}
static void oled_exit(void)
{
if(flag)
{
gpio_free(CS);
gpio_free(DC);
gpio_free(RES);
gpio_free(DIN);
gpio_free(CLK);
}
device_destroy(oled_class,oled_devno);
class_destroy(oled_class);
cdev_del(&oled_dev);
unregister_chrdev_region(oled_devno, 1);
printk(KERN_INFO"OLED exit\n");
}
module_init(oled_init);
module_exit(oled_exit);
MODULE_LICENSE("GPL");
Makefile:
//Makefile
ifneq ($(KERNELRELEASE),)
obj-m := oled.o
else
KERNELDIR:=/home/rpi/linux/
PWD := $(shell pwd)
CROSS_COMPILE := arm-linux-gnueabihf-
default:
$(MAKE) CROSS_COMPILE=$(CROSS_COMPILE) ARCH=arm -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.c *.order *.symvers
endif
However, when I wrote a program to open the device and write characters into it, there was no response from this OLED. And no error was logged into kern.log. What I really don't understand is why they behaved differently with the same control functions? Is there something fatal that I ignored?

Related

ZMQ_SNDBUF&&ZMQ_RCVBUF on ZMQ_PUB&&ZMQ_SUB no effect

Issue description
I used ZMQ_SNDBUF && ZMQ_RCVBUF on ZMQ_PUB&&ZMQ_SUB no effect.
But I executed the following command and it worked.
sudo sysctl -w net.core.wmem_default=5000
Before modifying net.core.wmem_default
The receiving end continues to receive 3757 frames and then refresh.
After modifying net.core.wmem_default
The receiving end continues to receive 22 frames and then refreshes.
Environment
libzmq version (commit hash if unreleased):
4.3.3
OS:
ubuntu18.04
Is that why?
Code
sender
//
// Created by kongshui on 22-8-23.
//
#include <unistd.h>
#include <iostream>
#include <zmq.hpp>
void main()
{
const int first_count = 10000000;
int hwm = 5;
int time = 10;
auto con = zmq_ctx_new();
// Set up bind socket
void *pub_socket = zmq_socket(con, ZMQ_PUB);
zmq_setsockopt(pub_socket, ZMQ_SNDTIMEO, &time, sizeof(time));
zmq_setsockopt(pub_socket, ZMQ_RCVTIMEO, &time, sizeof(time));
zmq_setsockopt(pub_socket, ZMQ_SNDHWM, &hwm, sizeof(hwm));
zmq_setsockopt(pub_socket, ZMQ_RCVHWM, &hwm, sizeof(hwm));
zmq_bind(pub_socket, "ipc:///tmp/qos_out");
int buf_size = 5000;
auto rrr = zmq_setsockopt(pub_socket, ZMQ_SNDBUF, &buf_size, sizeof(buf_size));
printf("rrr: %d", rrr);
hwm = 10;
size_t hwm_size = sizeof(hwm);
rrr = zmq_getsockopt(pub_socket, ZMQ_SNDBUF, &hwm, &hwm_size);
printf("rrr: %d, size: %d\n", rrr, hwm);
sleep(3);
// Send messages
int send_count = 0;
int recv_count = 0;
std::string msg;
while (send_count < first_count)
{
msg = std::to_string(send_count);
int res = zmq_send(pub_socket, msg.c_str(), msg.length(), ZMQ_DONTWAIT);
printf("res:%d, msg:%s", res, msg.c_str());
if (msg.length() == res)
++send_count;
else
break;
usleep(1000);
}
// Clean up
zmq_close(pub_socket);
}
receiver
//
// Created by kongshui on 22-8-23.
//
#include <unistd.h>
#include <iostream>
#include <zmq.hpp>
void main()
{
const int first_count = 15;
int hwm = 5;
int time = 10;
auto con = zmq_ctx_new();
hwm = 10;
// Set up connect socket
void *sub_socket = zmq_socket(con, ZMQ_SUB);
zmq_setsockopt(sub_socket, ZMQ_SNDTIMEO, &time, sizeof(time));
zmq_setsockopt(sub_socket, ZMQ_RCVTIMEO, &time, sizeof(time));
zmq_setsockopt(sub_socket, ZMQ_SNDHWM, &hwm, sizeof(hwm));
zmq_setsockopt(sub_socket, ZMQ_RCVHWM, &hwm, sizeof(hwm));
int buf_size = 5000;
std::string topic = "www";
auto rrr = zmq_setsockopt(sub_socket, ZMQ_RCVBUF, &buf_size, sizeof(buf_size));
printf("rrr: %d", rrr);
hwm = 10;
size_t hwm_size = sizeof(hwm);
rrr = zmq_getsockopt(sub_socket, ZMQ_RCVBUF, &hwm, &hwm_size);
printf("rrr: %d, size: %d\n", rrr, hwm);
zmq_connect(sub_socket, "ipc:///tmp/qos_out");
// zmq_setsockopt(sub_socket, ZMQ_SUBSCRIBE, topic.c_str(), topic.size());
zmq_setsockopt(sub_socket, ZMQ_SUBSCRIBE, nullptr, 0);
sleep(3);
// Send messages
int send_count = 0;
int recv_count = 0;
std::string msg;
char res[1024] = {0};
while (zmq_recv(sub_socket, res, 1021, ZMQ_DONTWAIT) > 0)
{
++recv_count;
printf("res:%s", res);
printf("first_count: %d, recv_count: %d\n", first_count, recv_count);
memset(res, 0, sizeof(res));
}
while (1)
{
if (zmq_recv(sub_socket, res, 1021, ZMQ_DONTWAIT) > 0)
{
++recv_count;
printf("res:%s", res);
memset(res, 0, sizeof(res));
printf("first_count: %d, recv_count: %d\n", first_count, recv_count);
sleep(1);
}
}
// Clean up
zmq_close(sub_socket);
}

Error with the output of Camera Calibration OPENCV 3.2 with C++ Visual Studio 2015. Cant save output value

i am getting an error when using opencv camera calibration. When i debug my code, it just open the webcam not show the camera calibration value output in Folder Location.
i am using opencv 3.2 with VS 15
My code:
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/aruco.hpp"
#include "opencv2/calib3d.hpp"
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
const float calibrationSquareDimension = 0.01905f; //meters
const float arucoSquareDimension = 0.1016f; //meters
const Size chessboardDimensions = Size(9,6);
void createArucoMarkers()
{
Mat outputMarker;
Ptr<aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
for (int i = 0; i < 50; i++)
{
aruco::drawMarker(markerDictionary, i, 500, outputMarker, 1);
ostringstream convert;
string imageName = "4x4Marker_";
convert << imageName << i << ".jpg";
imwrite(convert.str(), outputMarker);
}
}
void createKnownBoardPosition(Size boardsize, float squareEdgeLength, vector<Point3f>& corners)
{
for (int i = 0; i < boardsize.height; i++)
{
for (int j = 0; j < boardsize.width; j++)
{
corners.push_back(Point3f(j * squareEdgeLength, i * squareEdgeLength, 0.0f));
}
}
}
void getchessboardcorners(vector<Mat> images, vector<vector<Point2f>>& allfoundcorners, bool showresults = false)
{
for (vector<Mat>::iterator iter = images.begin(); iter != images.end(); iter++)
{
vector<Point2f> pointBuf;
bool found = findChessboardCorners(*iter, Size(9, 6), pointBuf, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
if (found)
{
allfoundcorners.push_back(pointBuf);
}
if (showresults)
{
drawChessboardCorners(*iter, Size(9, 6), pointBuf, found);
imshow("Looking for Corners", *iter);
waitKey(0);
}
}
}
void cameraCalibration(vector<Mat> calibrationImages, Size boardSize, float squareEdgeLength, Mat& cameraMatrix, Mat& distanceCoefficients)
{
vector<vector<Point2f>> checkerboardImageSpacePoints;
getchessboardcorners(calibrationImages, checkerboardImageSpacePoints, false);
vector<vector<Point3f>> worldSpaceCornerPoints(1);
createKnownBoardPosition(boardSize, squareEdgeLength, worldSpaceCornerPoints[0]);
worldSpaceCornerPoints.resize(checkerboardImageSpacePoints.size(), worldSpaceCornerPoints[0]);
vector<Mat> rVectors, tVectors;
distanceCoefficients = Mat::zeros(8, 1, CV_64F);
calibrateCamera(worldSpaceCornerPoints, checkerboardImageSpacePoints, boardSize, cameraMatrix, distanceCoefficients, rVectors, tVectors );
}
bool saveCameraCalibration(string name, Mat cameraMatrix, Mat distanceCoefficients)
{
ofstream outStream(name);
if (outStream)
{
uint16_t rows = cameraMatrix.rows;
uint16_t columns = cameraMatrix.cols;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
double value = cameraMatrix.at<double>(r, c);
outStream << value << endl;
}
}
rows = distanceCoefficients.rows;
columns = distanceCoefficients.cols;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
double value = cameraMatrix.at<double>(r, c);
outStream << value << endl;
}
}
outStream.close();
return true;
}
return false;
}
int main(int argv, char** argc)
{
Mat frame;
Mat drawToFrame;
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
Mat distanceCoefficients;
vector<Mat> savedImages;
vector<vector<Point2f>> markerCorners, rejectedCandidates;
VideoCapture vid(0);
if (!vid.isOpened())
{
return 0;
}
int framesPersecond = 20;
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
while (true)
{
if (!vid.read(frame))
break;
vector<Vec2f> foundPoints;
bool found = false;
found = findChessboardCorners(frame, chessboardDimensions, foundPoints, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE );
frame.copyTo(drawToFrame);
drawChessboardCorners(drawToFrame, chessboardDimensions, foundPoints, found);
if (found)
imshow("Webcam", drawToFrame);
else
imshow("Webcam", frame);
char character = waitKey(1000 / framesPersecond);
switch (character)
{
case ' ':
//saving image
if(found)
{
Mat temp;
frame.copyTo(temp);
savedImages.push_back(temp);
}
break;
case 13:
//start calibration
if (savedImages.size() > 15)
{
cameraCalibration(savedImages, chessboardDimensions, calibrationSquareDimension, cameraMatrix, distanceCoefficients);
saveCameraCalibration("CameraCalibration", cameraMatrix, distanceCoefficients);
}
break;
case 27:
//exit
return 0;
break;
}
}
return 0;
}

many pipes in a shell program

I have to create support for one or more pipes in my shell, for example:ls /tmp | wc -l or sort foo | uniq -c | wc -l. But I have no idea how to do it. I have read many tutorials but I can't adjust what I read in my code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_CMD_LENGTH 100
#define MAX_NUM_PARAMS 10
int parsecmd(char* cmd, char** params) { //split cmd into array of params
int i,n=-1;
for(i=0; i<MAX_NUM_PARAMS; i++) {
params[i] = strsep(&cmd, " ");
n++;
if(params[i] == NULL) break;
}
return(n);
};
int executecmd(char** params) {
pid_t pid = fork(); //fork process
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
} else if (pid == 0) { // child process
execvp(params[0], params); //exec cmd
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
int childstatus;
waitpid(pid, &childstatus, 0);
return 1;
}
};
int execpipe (char ** argv1, char ** argv2) {
int fds[2];
pipe(fds);
int i;
pid_t pid = fork();
if (pid == -1) { //error
char *error = strerror(errno);
printf("error fork!!\n");
return 1;
}
if (pid == 0) { // child process
close(fds[1]);
dup2(fds[0], 0);
//close(fds[0]);
execvp(argv2[0], argv2); // run command AFTER pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
} else { // parent process
close(fds[0]);
dup2(fds[1], 1);
//close(fds[1]);
execvp(argv1[0], argv1); // run command BEFORE pipe character in userinput
char *error = strerror(errno);
printf("unknown command\n");
return 0;
}
};
int main() {
char cmd[MAX_CMD_LENGTH+1];
char * params[MAX_NUM_PARAMS+1];
char * argv1[MAX_NUM_PARAMS+1] = {0};
char * argv2[MAX_NUM_PARAMS+1] = {0};
int k, y, x;
int f = 1;
while(1) {
printf("$"); //prompt
if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; //read command, ctrl+D exit
if(cmd[strlen(cmd)-1] == '\n') { //remove newline char
cmd[strlen(cmd)-1] = '\0';
}
int j=parsecmd(cmd, params); //split cmd into array of params
if (strcmp(params[0], "exit") == 0) break; //exit
for (k=0; k <j; k++) { //elegxos gia uparksi pipes
if (strcmp(params[k], "|") == 0) {
f = 0; y = k;
printf("pipe found\n");
break;
}
}
if (f==0) {
for (x=0; x<k; x++) {
argv1[x]=params[x];
}
int z = 0;
for (x=k+1; x< j; x++) {
argv2[z]=params[x];
z++;
}
if (execpipe(argv1, argv2) == 0) break;
} else if (f==1) {
if (executecmd(params) == 0) break;
}
} // end while
return 0;
}

Unable to communicate between libwebsocket as client and socket.io as server

This is client code by using libwebsocket version 1.5
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <syslog.h>
#include <sys/time.h>
#include <unistd.h>
#include <libwebsockets.h>
static volatile int force_exit = 0;
static int state, command_received = 0, forked = 0;
#define MAX_ECHO_PAYLOAD 1400
#define LOCAL_RESOURCE_PATH "./"
struct per_session_data {
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_ECHO_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
unsigned int len;
};
//for temporary storing data from tcpdump
struct per_session_data data1;
static int callback_echo(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
{
struct per_session_data *pss = (struct per_session_data *)user;
int n;
switch (reason) {
/* when the callback is used for client operations --> */
case LWS_CALLBACK_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf("Closed\n");
state = 0;
break;
case LWS_CALLBACK_ESTABLISHED:
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf("Client connected\n");
state = 2;
break;
/* we will receive our packet here*/
case LWS_CALLBACK_RECEIVE:
case LWS_CALLBACK_CLIENT_RECEIVE:
printf("Rx from server: %s\n", (char *)in);
if (!strcmp((char *)in, "tcpdump"))
{
command_received = 1;
}
break;
/* we will send our packet here */
case LWS_CALLBACK_CLIENT_WRITEABLE:
printf("client writing to server\n");
pss->len = sprintf((char *)&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", data1.buf + LWS_SEND_BUFFER_PRE_PADDING);
n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
printf("Data: %s\n\n\n\n\n\n\n", &pss->buf[LWS_SEND_BUFFER_PRE_PADDING]);
//error handling for write fail and partial writes
if (n < 0) {
printf("ERROR %d writing to socket, hanging up\n", n);
return -1;
}
if (n < (int)pss->len) {
printf("Partial write\n");
return -1;
}
break;
default:
printf("default...\n");
break;
}
return 0;
}
/* List of available protocols */
static struct libwebsocket_protocols protocols[] = {
{
"default", /* name */
callback_echo, /* callback */
sizeof(struct per_session_data) /* per_session_data_size */
},
{
NULL, NULL, 0 /* End of list */
}
};
void sighandler(int sig)
{
force_exit = 1;
}
int main(int argc, char **argv)
{
//pipe stuff
int pipe_fd[2];
if (pipe(pipe_fd) < 0)
{
perror("PIPE:");
exit(-1);
}
//for libwebsocket_service
int n = 0;
//test port can be overidden
int port = 9000;
struct libwebsocket_context *context;
int opts = 0;
char interface_name[128] = "";
const char *interface = NULL;
int use_ssl = 0;
char ssl_cert[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
char ssl_key[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
int listen_port = 80;
struct lws_context_creation_info info;
char passphrase[256];
char uri[256] = "/";
char address[256], ads_port[256 + 30];
//lws servicing time intervals
int rate_us = 250000;
unsigned int oldus = 0;
struct libwebsocket *wsi;
//should check this
int debug_level = 2;
memset(&info, 0, sizeof info);
lwsl_notice("Built to support client operations\n");
//re-configuring server ip and port here
if (argc == 3)
{
strncpy(address, argv[1], sizeof(address) - 1);
address[sizeof(address) - 1] = '\0';
port = atoi(argv[2]);
}
else if (argc == 1)
{
strncpy(address, "localhost", sizeof(address) - 1);
address[sizeof(address) - 1] = '\0';
port = 9000;
}
else
{
printf("Try: ./client.exec <ip> <port>\n");
exit(-1);
}
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", 0, LOG_DAEMON);
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
lwsl_notice("libwebsockets echo test - "
"(C) Copyright 2010-2015 Andy Green <andy#warmcat.com> - "
"licensed under LGPL2.1\n");
lwsl_notice("Running in client mode\n");
listen_port = CONTEXT_PORT_NO_LISTEN;
lwsl_info("requiring server cert validation againts %s\n", ssl_cert);
info.ssl_ca_filepath = ssl_cert;
info.port = listen_port;
info.iface = interface;
info.protocols = protocols;
#ifndef LWS_NO_EXTENSIONS
info.extensions = libwebsocket_get_internal_extensions();
#endif
info.gid = -1;
info.uid = -1;
info.options = opts;
context = libwebsocket_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return -1;
}
signal(SIGINT, sighandler);
n = 0;
while (n >= 0 && !force_exit)
{
//do connect only once
if (!state) {
state = 1;
printf("Client connecting to %s:%u....\n", address, port);
address[sizeof(address) - 1] = '\0';
sprintf(ads_port, "%s:%u", address, port & 65535);
wsi = libwebsocket_client_connect(context, address, port, use_ssl, uri, ads_port, ads_port, NULL, -1);
if (!wsi) {
printf("Client failed to connect to %s:%u\n", address, port);
goto bail;
}
}
if (command_received == 1 && !forked)
{
printf("Going to fork\n");
forked = 1;
pid_t child_pid = fork();
if (child_pid == -1)
{
perror("FORK:");
exit(-1);
}
else if (child_pid == 0)
{
close(pipe_fd[0]);
printf("Starting tcpdump\n");
if (dup2(pipe_fd[1], 1) < 0)
{
perror("DUP2:");
exit(-1);
}
//closing the connection to server for child
libwebsocket_context_destroy(context);
closelog();
char *cmd[] = {"tcpdump", "-i", "any", NULL};
if (execv("/usr/sbin/tcpdump", cmd) < 0)
{
perror("EXECV:");
exit(-1);
}
}
}
/* if (forked == 1)
{
close(pipe_fd[1]);
}
*/
if (command_received == 1)
{
//stay here if the pipe is empty else try to read max 1400 bytes of data
while ((data1.len = read(pipe_fd[0], data1.buf + LWS_SEND_BUFFER_PRE_PADDING, 1400)) <= 0);
//check if server wants any service
//printf("%s\n\n\n\n\n\n\n", data1.buf + LWS_SEND_BUFFER_PRE_PADDING);
libwebsocket_callback_on_writable(context, wsi);
}
//This fn times out every 10usec
n = libwebsocket_service(context, 10);
}
//bail: jump from while loop also if connect fails
bail:
libwebsocket_context_destroy(context);
printf("libwebsockets-test-echo exited cleanly\n");
closelog();
return 0;
}
This is my server code by using socket.io
var io = require('socket.io')();
var middleware = require('socketio-wildcard')();
io.use(middleware);
io.on('connection', function(socket) {
console.log('On socket connection')
socket.on('*', function(event, data){
console.log("---- Event ----- : " + JSON.stringify(event));
console.log("---- Data ----- : " + JSON.stringify(data))
});
});
io.listen(9000, 'localhost');
The client is unable to connect with server. when i tested client with strace it infinitely does receive as below
recv(8, "", 1, 0) = 0
recv(8, "", 1, 0) = 0
recv(8, "", 1, 0) = 0
.
.
.
.
Please point out my mistake. Any help is appreciated.
Thanks

Kernel module still in use afther executing `$ echo 3 > /dev/tlc5947` (reference counting error)

Hellow I'm tring to learn writing kernel modules and device drivers. As a begginig I decided to start by making a driver for my tlc5947 led matrix. From simple kernel module with parameters I moved to char device driver but I'm having hard time with resource reference counting. Whole day I have been playing the restart game with my PI and still can't figure from where the bug is comming ...
This is the module header:
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#ifndef _TLC5947_LED_MATRIX_H
#define _TLC5947_LED_MATRIX_H
#define TLC5947_GPIOS 3
#define TLC5947_LEDS 24
#define TLC5947_MAXPWM 4096
#define GPIO_HIGH 1
#define GPIO_LOW 0
#define TLC5947_NAME "tlc5947"
#define CONST_PARAM S_IRUSR | S_IRGRP | S_IROTH
ushort tlc5947_chips = 255;
ushort tlc5947_data = 255;
ushort tlc5947_clock = 255;
ushort tlc5947_latch = 255;
static struct gpio tlc5947[TLC5947_GPIOS] = {
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 DATA"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 CLOCK"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 LATCH"},
};
static dev_t tlc5947_numbers;
static int tlc5947_major_number;
static int tlc5947_first_minor = 0;
static unsigned int tlc5947_minor_count = 1;
static struct file_operations tlc5947_file_operations;
static struct cdev* tlc5947_cdev;
static int tlc5947_file_opened = 0;
static int tlc5947_file_open(struct inode* inode, struct file* file);
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset);
static int tlc5947_file_close(struct inode* inode, struct file* file);
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name);
static int __init tlc5947_init(void);
static void __exit tlc5947_exit(void);
#endif
The source:
#include "tlc5947_led_matrix.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
module_param(tlc5947_chips, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_chips, "Number of tlc5967 chips that are chain connected.");
module_param(tlc5947_data, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_data, "Number of gpio pin on wich DATA signal is connected (BCM Enum).");
module_param(tlc5947_clock, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_clock, "Number of gpio pin on wich CLOCK signal is connected (BCM Enum).");
module_param(tlc5947_latch, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_latch, "Number of gpio pin on wich LATCH signal is connected (BCM Enum).");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ivo Stratev");
MODULE_DESCRIPTION("Basic Linux Kernel module using GPIOs to drive tlc5947");
MODULE_SUPPORTED_DEVICE(TLC5947_NAME);
static int tlc5947_file_open(struct inode* inode, struct file* file) {
if(tlc5947_file_opened == 1) {
printk(KERN_ERR "Fail to open file /dev/%s\n", TLC5947_NAME);
return -EBUSY;
}
tlc5947_file_opened = 1;
return 0;
}
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset) {
char data[10];
unsigned int i;
unsigned long copy_ret = copy_from_user(data, buffer, buffer_length);
if(copy_ret) {
printk(KERN_ERR "Error while copying data\nCalling copy_from_user reurned%ld\n", copy_ret);
return copy_ret;
}
data[0] -= '0';
i = tlc5947_chips * TLC5947_LEDS - 1;
gpio_set_value(tlc5947_latch, GPIO_LOW);
while(1) {
unsigned char bit = 11;
while(1) {
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_data, (data[0] & (1 << bit)) ? GPIO_HIGH : GPIO_LOW);
gpio_set_value(tlc5947_clock, GPIO_HIGH);
if(bit == 0) {
break;
}
bit--;
}
if(i == 0) {
break;
}
i--;
}
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_latch, GPIO_HIGH);
gpio_set_value(tlc5947_latch, GPIO_LOW);
return copy_ret;
}
static int tlc5947_file_close(struct inode* inode, struct file* file) {
tlc5947_file_opened = 0;
return 0;
}
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name) {
int is_255 = (*tlc5947_param) == 255;
if(is_255) {
printk(KERN_ERR "Parameter %s value not setted when loading the module\n", tlc5947_param_name);
}
return is_255;
}
static int __init tlc5947_init(void) {
int init_ret = 0;
init_ret |= is_tlc5947_param_set(&tlc5947_chips, "tlc5947_chips");
init_ret |= is_tlc5947_param_set(&tlc5947_data, "tlc5947_data");
init_ret |= is_tlc5947_param_set(&tlc5947_clock, "tlc5947_clock");
init_ret |= is_tlc5947_param_set(&tlc5947_latch, "tlc5947_latch");
if(init_ret) {
return -EINVAL;
}
tlc5947[0].gpio = tlc5947_data;
tlc5947[1].gpio = tlc5947_clock;
tlc5947[2].gpio = tlc5947_latch;
init_ret = gpio_request_array(tlc5947, TLC5947_GPIOS);
if(init_ret) {
printk(KERN_ERR "Unable to request GPIOs!\nCalling gpio_request_array returned %d\n", init_ret);
return init_ret;
}
init_ret = alloc_chrdev_region(&tlc5947_numbers, tlc5947_first_minor, tlc5947_minor_count, TLC5947_NAME);
if(init_ret) {
printk(KERN_ERR "Could not allocate device numbers\nCalling alloc_chrdev_region returned %d\n", init_ret);
return init_ret;
}
tlc5947_major_number = MAJOR(tlc5947_numbers);
printk(KERN_INFO "Device major number is %d. Use $ sudo make device\n", tlc5947_major_number);
tlc5947_cdev = cdev_alloc();
tlc5947_cdev->owner = THIS_MODULE;
tlc5947_file_operations.owner = THIS_MODULE;
tlc5947_file_operations.open = tlc5947_file_open;
tlc5947_file_operations.release = tlc5947_file_close;
tlc5947_file_operations.write = tlc5947_file_write;
tlc5947_cdev->ops = &tlc5947_file_operations;
init_ret = cdev_add(tlc5947_cdev, tlc5947_numbers, tlc5947_minor_count);
if(init_ret) {
printk(KERN_ERR "Failed to add device numbers to struct cdev\nCalling cdev_add returned %d\n", init_ret);
return init_ret;
}
return 0;
}
static void __exit tlc5947_exit(void) {
cdev_del(tlc5947_cdev);
unregister_chrdev_region(tlc5947_numbers, tlc5947_minor_count);
gpio_free_array(tlc5947, TLC5947_GPIOS);
}
module_init(tlc5947_init);
module_exit(tlc5947_exit);
And the makefile:
target = tlc5947
driver = tlc5947_led_matrix
obj-m := $(target).o
$(target)-objs := $(driver).o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f /dev/$(target)
activate:
insmod $(target).ko tlc5947_chips=8 tlc5947_data=17 tlc5947_clock=27 tlc5947_latch=22
remove:
rmmod -rf $(target)
modprobe -rf $(target)
device:
mknod /dev/$(target) c 243 0
chmod 777 /dev/$(target)

Resources