Created
January 5, 2016 09:57
-
-
Save AndreiDuma/21ec0a01d6580708170b to your computer and use it in GitHub Desktop.
SI EpicClock
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
#include <linux/module.h> | |
#include <linux/init.h> | |
#include <linux/gpio.h> | |
#include <linux/hrtimer.h> | |
#include <linux/ktime.h> | |
#include <linux/fs.h> | |
#include <linux/kernel.h> | |
#include <linux/uaccess.h> | |
MODULE_DESCRIPTION("Epiclock Module"); | |
MODULE_AUTHOR("SI"); | |
MODULE_LICENSE("GPL"); | |
static int open(struct inode *, struct file *); | |
static int release(struct inode *, struct file *); | |
static int read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset); | |
static int write(struct file *file, const char __user *user_buffer, size_t size, loff_t *offset); | |
static struct file_operations fops = { | |
.open = open, | |
.release = release, | |
.read = read, | |
.write = write, | |
}; | |
static int major; // our assigned major number | |
static atomic_t used; // 0 - led is available, 1 - led is already opened | |
static int state; // 0 - led is off, 1 - led is on | |
#define MS_TO_NS(x) (x * 1E6L) | |
#define BLINK_DELAY 1 | |
int digits[10][7] = | |
{ | |
{1,1,1,1,1,1,0}, //0 | |
{0,1,1,0,0,0,0}, //1 | |
{1,1,0,1,1,0,1}, //2 | |
{1,1,1,1,0,0,1}, //3 | |
{0,1,1,0,0,1,1}, //4 | |
{1,0,1,1,0,1,1}, //5 | |
{1,0,1,1,1,1,1}, //6 | |
{1,1,1,0,0,0,0}, //7 | |
{1,1,1,1,1,1,1}, //8 | |
{1,1,1,1,0,1,1}, //9 | |
}; | |
int seg[7] ={7,11,8,9,25,10,24};//25, 24, 23, 22, 27, 18, 17}; | |
int en[8] = {22,23,27,18,17,2,14,4};//11, 10, 9, 8, 7, 4}; | |
//saves the digit to display on the corresponding position | |
//0-9 the digits to display, except the last 2 elements, were 1 means enable the dots, 0 disable | |
//the last two elements control the dots | |
static int saved_digit[8]={0}; | |
static struct hrtimer hr_timer; | |
static ktime_t ktime_period; | |
/* Enables the correspondings segments of the digit | |
* /param n The number to display | |
*/ | |
void digit(int n) | |
{ | |
/* sanity checks*/ | |
//TODO 1 - read above; | |
int i; | |
for (i = 0; i < 7; i++) { | |
gpio_set_value(seg[i], digits[n][i]); | |
} | |
} | |
/* Enables the driver to turn on one of the digits | |
* \param d Line of the driver to be enabled, -1 for none | |
*/ | |
void enable(int d) | |
{ | |
//TODO 1 - read above; | |
int i; | |
for (i = 0; i < 6; i++) { | |
gpio_set_value(en[i], 0); | |
} | |
if (d == -1) { | |
return; | |
} | |
gpio_set_value(en[d], 1); | |
} | |
/* Timer callback to update display | |
*/ | |
enum hrtimer_restart epiclock_update(struct hrtimer* timer) | |
{ | |
static unsigned pos = 0; | |
ktime_t kt_now; | |
int ret; | |
//TODO 1 - increment pos and display the digit in the coresponding position | |
enable(pos); | |
digit(saved_digit[pos]); | |
pos = (pos + 1) % 6; | |
kt_now = hrtimer_cb_get_time(&hr_timer); | |
ret = hrtimer_forward(&hr_timer, kt_now, ktime_period); | |
return HRTIMER_RESTART; | |
} | |
static int __init epiclock_init(void) | |
{ | |
int i; | |
ktime_t ktime; | |
printk(KERN_INFO "epiclock: loading\n"); | |
/* initialize all signals to output, but off */ | |
for(i = 0; i < 7; i++) | |
{ | |
gpio_direction_output(seg[i], 0); | |
} | |
for(i = 0; i < 8; i++) | |
{ | |
gpio_direction_output(en[i], 0); | |
} | |
/* set up the timer for the first time */ | |
ktime_period = ktime_set(0, MS_TO_NS(BLINK_DELAY)); | |
hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | |
hr_timer.function = epiclock_update; | |
hrtimer_start(&hr_timer, ktime, HRTIMER_MODE_REL); | |
// register as chardev and get our major number | |
if((major = register_chrdev(0, "epic_clock", &fops)) < 0) | |
return major; | |
return 0; | |
} | |
static void __exit epiclock_cleanup(void) | |
{ | |
printk(KERN_INFO "epiclock: unloading...\n"); | |
/* disable timer */ | |
hrtimer_cancel(&hr_timer); | |
unregister_chrdev(major, "epic_clock"); | |
/* disable all digits and points */ | |
enable(-1); | |
} | |
static int open(struct inode *inode, struct file *file) | |
{ | |
// led becomes used if it was previously unused, otherwise EPERM | |
if(atomic_cmpxchg(&used, 0, 1) != 0) | |
return -EPERM; | |
return 0; | |
} | |
static int release(struct inode *inode, struct file *file) | |
{ | |
int old_used; | |
// led becomes unused | |
if((old_used = atomic_cmpxchg(&used, 1, 0)) != 1) | |
printk(KERN_ERR "closing device that was not opened; state is %d\n", old_used); | |
return 0; | |
} | |
static int read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset) | |
{ | |
//DO NOT TOUCH THIS. | |
return 0; | |
} | |
static int write(struct file *file, const char __user *user_buffer, size_t size, loff_t *offset) | |
{ | |
// UGLY HACK - ignore concurrency issues | |
// even if we allow only one process to open the device | |
// we can still get concurrent accesses from a multithreaded process | |
//TODO 2 - read data from userspace | |
char buf[6]; | |
if (size < 6) { | |
return 0; | |
} | |
copy_from_user(buf, user_buffer, 6); | |
int i; | |
for (i = 0; i < 6; i++) { | |
saved_digit[i] = buf[i] - '0'; | |
} | |
return 6; | |
} | |
module_init(epiclock_init); | |
module_exit(epiclock_cleanup); |
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
obj-m = epicclock.o |
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
ARCH := arm | |
CROSS_COMPILE := arm-linux-gnueabihf- | |
KDIR := /opt/rpi/kernel | |
PWD := $(shell pwd) | |
obj-m := epicclock.o | |
kbuild: | |
make -C $(KDIR) M=`pwd` ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules | |
clean: | |
make -C $(KDIR) M=`pwd` clean | |
-rm -f *~ Module.symvers Module.markers modules.order | |
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
while [ true ]; do | |
date +%H%M%S #> /dev/ec | |
sleep 2 | |
date +%d%m%y #> /dev/ec | |
sleep 2 | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment