├── .gitattributes ├── .gitignore ├── Chapter01 ├── BBB-uEnv.txt └── README.md ├── Chapter03 ├── README.md ├── module │ ├── Makefile │ └── dummy.c ├── picoc │ ├── picoc-drop-readline.patch │ └── picoc-git.tgz ├── pulse │ ├── Makefile │ ├── pulse-gpio.c │ ├── pulse-gpio_at91-sama5d3_xplained.dts.patch │ ├── pulse.c │ └── pulse.h └── pulse_gen.sh ├── Chapter04 ├── README.md ├── mydaemon │ ├── Makefile │ ├── mydaemon.c │ ├── mydaemon.php │ ├── mydaemon.py │ └── mydaemon.sh ├── mysql │ ├── Makefile │ ├── my_dump.c │ ├── my_dump.php │ ├── my_dump.py │ ├── my_dump.sh │ ├── my_init.sh │ ├── my_set.c │ ├── my_set.php │ ├── my_set.py │ └── my_set.sh ├── syslogd │ ├── Makefile │ ├── logger.c │ ├── logger.php │ └── logger.py ├── webled │ ├── bash │ │ ├── httpd.sh │ │ ├── httpd_echo.sh │ │ ├── httpd_sh │ │ └── turn.cgi │ ├── php │ │ └── turn.php │ └── python │ │ ├── httpd.py │ │ └── httpd_show_info.py └── xinetd │ ├── echo.sh │ └── echo_sh ├── Chapter05 ├── README.md ├── openwrt-helloworld │ ├── Makefile │ └── src │ │ ├── Makefile │ │ └── helloworld.c └── phpdemo │ ├── demo_dump.php │ ├── demo_init.sh │ └── demo_set.sh ├── Chapter06 ├── BB-LEDS-C6-00A0.dts ├── README.md ├── gpio-irq │ ├── Makefile │ ├── gpio-irq.c │ └── gpio-irq.c.OK ├── gpio-poll.php ├── gpio-poll.py └── gpio-poll │ ├── Makefile │ ├── gpio-poll │ └── gpio-poll.c ├── Chapter07 ├── README.md ├── rfid_lf.py └── scat │ ├── Makefile │ └── scat.c ├── Chapter08 ├── README.md ├── key_read.py └── usb_sendrecv │ ├── Makefile │ └── usb_sendrecv.c ├── Chapter09 ├── A5D3-IIO-HTU21D+T5403-dts.patch ├── A5D3-TTY-SC16IS7-dts.patch ├── BB-ADC-MCP322-00A0.dts ├── BB-EEPROM-A24-00A0.dts ├── BB-IOEXP-MCP23-00A0.dts ├── README.md ├── i2c_dac │ ├── Makefile │ └── i2c_dac.c └── i2c_temp.py ├── Chapter10 ├── A5D3-TTY-SC16IS7-dts.patch ├── A5D3-digital-IO-spi.patch ├── README.md ├── digital.py ├── imx6qdl-wandboard-spidev.dtsi.patch └── spi_thermo │ ├── Makefile │ └── spi_thermo.c ├── Chapter11 ├── BB-W1-GPIO-00A0.dts └── README.md ├── Chapter12 ├── README.md ├── tcp_cli.py └── tcp_srv.py ├── Chapter13 ├── README.md ├── hostapd.conf └── udhcpd.conf.br0 ├── Chapter14 ├── BB-DCAN1-00A0.dts ├── README.md ├── imx6qdl-wandboard-mcp2515.dtsi.patch └── socketcan │ ├── Makefile │ └── socketcan_send.c ├── Chapter15 ├── README.md ├── audio-codec-wm8731.patch ├── tone-sine-1000hz.m4a ├── tone-sine-1000hz.mp3 └── tone-sine-1000hz.wav ├── Chapter16 └── input_uvc.patch ├── Chapter17 ├── mq2.log ├── mq2.plot └── mq2.png ├── Chapter19 ├── gsm │ └── myisp ├── rfid │ ├── Makefile │ ├── libavp.tgz │ ├── libcaenrfid.tgz │ ├── libmsgbuff.tgz │ └── rfid_uhf.c ├── smartcard │ ├── add_TSC12xxF_reader.patch │ └── smart_card.py └── zwave │ ├── open-zwave-control-panel.tgz │ └── open-zwave.tgz ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Chapter01/BBB-uEnv.txt: -------------------------------------------------------------------------------- 1 | loadaddr=0x82000000 2 | fdtaddr=0x88000000 3 | rdaddr=0x88080000 4 | 5 | initrd_high=0xffffffff 6 | fdt_high=0xffffffff 7 | mmcroot=/dev/mmcblk0p1 8 | 9 | loadximage=load mmc 0:1 ${loadaddr} /boot/vmlinuz-${uname_r} 10 | loadxfdt=load mmc 0:1 ${fdtaddr} /boot/dtbs/${uname_r}/${fdtfile} 11 | loadxrd=load mmc 0:1 ${rdaddr} /boot/initrd.img-${uname_r}; setenv rdsize ${filesize} 12 | loaduEnvtxt=load mmc 0:1 ${loadaddr} /boot/uEnv.txt ; env import -t ${loadaddr} ${filesize}; 13 | loadall=run loaduEnvtxt; run loadximage; run loadxfdt; 14 | mmcargs=setenv bootargs console=tty0 console=${console} ${optargs} ${cape_disable} ${cape_enable} root=${mmcroot} rootfstype=${mmcrootfstype} ${cmdline} 15 | 16 | uenvcmd=run loadall; run mmcargs; bootz ${loadaddr} - ${fdtaddr}; 17 | -------------------------------------------------------------------------------- /Chapter01/README.md: -------------------------------------------------------------------------------- 1 | Chapter 1 - Installing the Developing System 2 | ============================================ 3 | 4 | Here the code from chapter 1 - "Installing the Developing System" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here is an U-Boot configuration file for the BeagleBone Black. 9 | 10 | See the URL 11 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 12 | for further info. 13 | -------------------------------------------------------------------------------- /Chapter03/README.md: -------------------------------------------------------------------------------- 1 | Chapter 3 - C compiler, device drivers & useful developing techniques 2 | ===================================================================== 3 | 4 | Here the code from chapter 3 - "C compiler, device drivers & useful developing 5 | techniques" of the book "GNU/Linux Rapid Embedded Programming" written by 6 | Rodolfo Giometti and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some exmaples about how a kernel module works, an example of very 9 | simple device driver and the code of a C interpreter we used in the book to 10 | show how to use a compiler or a cross-compiler. 11 | 12 | See the URL 13 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 14 | for further info. 15 | -------------------------------------------------------------------------------- /Chapter03/module/Makefile: -------------------------------------------------------------------------------- 1 | ifndef KERNEL_DIR 2 | $(error KERNEL_DIR must be set in the command line) 3 | endif 4 | PWD := $(shell pwd) 5 | 6 | # This specifies the kernel module to be compiled 7 | obj-m += dummy.o 8 | 9 | # The default action 10 | all: modules 11 | 12 | # The main tasks 13 | modules clean: 14 | make -C $(KERNEL_DIR) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \ 15 | SUBDIRS=$(PWD) $@ 16 | -------------------------------------------------------------------------------- /Chapter03/module/dummy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* This is the function executed during the module loading */ 5 | static int dummy_module_init(void) 6 | { 7 | printk("dummy_module loaded!\n"); 8 | return 0; 9 | } 10 | 11 | /* This is the function executed during the module unloading */ 12 | static void dummy_module_exit(void) 13 | { 14 | printk("dummy_module unloaded!\n"); 15 | return; 16 | } 17 | 18 | module_init(dummy_module_init); 19 | module_exit(dummy_module_exit); 20 | 21 | MODULE_AUTHOR("Rodolfo Giometti "); 22 | MODULE_LICENSE("GPL"); 23 | MODULE_VERSION("1.0.0"); 24 | -------------------------------------------------------------------------------- /Chapter03/picoc/picoc-drop-readline.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 6e01a17..c24d09d 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -1,6 +1,6 @@ 6 | CC=gcc 7 | CFLAGS=-Wall -pedantic -g -DUNIX_HOST -DVER=\"`svnversion -n`\" 8 | -LIBS=-lm -lreadline 9 | +LIBS=-lm 10 | 11 | TARGET = picoc 12 | SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \ 13 | diff --git a/platform.h b/platform.h 14 | index 2d7c8eb..c0b3a9a 100644 15 | --- a/platform.h 16 | +++ b/platform.h 17 | @@ -49,7 +49,6 @@ 18 | # ifndef NO_FP 19 | # include 20 | # define PICOC_MATH_LIBRARY 21 | -# define USE_READLINE 22 | # undef BIG_ENDIAN 23 | # if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) 24 | # define BIG_ENDIAN 25 | -------------------------------------------------------------------------------- /Chapter03/picoc/picoc-git.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter03/picoc/picoc-git.tgz -------------------------------------------------------------------------------- /Chapter03/pulse/Makefile: -------------------------------------------------------------------------------- 1 | ifndef KERNEL_DIR 2 | $(error KERNEL_DIR must be set in the command line) 3 | endif 4 | PWD := $(shell pwd) 5 | CROSS_COMPILE = arm-linux-gnueabihf- 6 | 7 | obj-m = pulse.o 8 | obj-m += pulse-gpio.o 9 | 10 | all: modules 11 | 12 | modules clean: 13 | $(MAKE) -C $(KERNEL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) \ 14 | SUBDIRS=$(PWD) $@ 15 | -------------------------------------------------------------------------------- /Chapter03/pulse/pulse-gpio.c: -------------------------------------------------------------------------------- 1 | #define PULSE_GPIO_NAME "pulse-gpio" 2 | #define pr_fmt(fmt) PULSE_GPIO_NAME ": " fmt 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pulse.h" 17 | 18 | struct pulse_gpio_priv { 19 | int num_pulses; 20 | struct { 21 | struct pulse_device *dev; 22 | int irq; 23 | } pulse[]; 24 | }; 25 | 26 | /* 27 | * IRQ handler 28 | */ 29 | 30 | static irqreturn_t irq_handler(int i, void *ptr, struct pt_regs *regs) 31 | { 32 | struct pulse_device *pulse = (struct pulse_device *) ptr; 33 | 34 | BUG_ON(!ptr); 35 | 36 | pulse_event(pulse); 37 | 38 | return IRQ_HANDLED; 39 | } 40 | 41 | /* 42 | * Platform driver stuff 43 | */ 44 | 45 | static inline int sizeof_pulse_gpio_priv(int num_pulses) 46 | { 47 | return sizeof(struct pulse_gpio_priv) + 48 | (sizeof(struct pulse_device) * num_pulses); 49 | } 50 | 51 | static int pulse_gpio_probe(struct platform_device *pdev) 52 | { 53 | struct device *dev = &pdev->dev; 54 | struct fwnode_handle *child; 55 | struct pulse_gpio_priv *priv; 56 | int count, ret; 57 | struct device_node *np; 58 | 59 | /* Get the number of defined pulse sources */ 60 | count = device_get_child_node_count(dev); 61 | if (!count) 62 | return -ENODEV; 63 | 64 | /* Allocate private data */ 65 | priv = devm_kzalloc(dev, sizeof_pulse_gpio_priv(count), GFP_KERNEL); 66 | if (!priv) 67 | return -ENOMEM; 68 | 69 | device_for_each_child_node(dev, child) { 70 | int irq, flags; 71 | struct gpio_desc *gpiod; 72 | const char *label, *trigger; 73 | struct pulse_device *new_pulse; 74 | 75 | /* Get the GPIO descriptor */ 76 | gpiod = devm_get_gpiod_from_child(dev, NULL, child); 77 | if (IS_ERR(gpiod)) { 78 | fwnode_handle_put(child); 79 | ret = PTR_ERR(gpiod); 80 | goto error; 81 | } 82 | gpiod_direction_input(gpiod); 83 | 84 | np = to_of_node(child); 85 | 86 | /* Get the GPIO's properties */ 87 | if (fwnode_property_present(child, "label")) { 88 | fwnode_property_read_string(child, "label", &label); 89 | } else { 90 | if (IS_ENABLED(CONFIG_OF) && !label && np) 91 | label = np->name; 92 | if (!label) { 93 | ret = -EINVAL; 94 | goto error; 95 | } 96 | } 97 | 98 | flags = 0; 99 | ret = fwnode_property_read_string(child, "trigger", &trigger); 100 | if (ret == 0) { 101 | if (strcmp(trigger, "rising") == 0) 102 | flags |= IRQF_TRIGGER_RISING; 103 | else if (strcmp(trigger, "fallng") == 0) 104 | flags |= IRQF_TRIGGER_FALLING; 105 | else if (strcmp(trigger, "both") == 0) 106 | flags |= IRQF_TRIGGER_RISING | \ 107 | IRQF_TRIGGER_FALLING; 108 | else { 109 | ret = -EINVAL; 110 | goto error; 111 | } 112 | } 113 | 114 | /* Register the new pulse device */ 115 | new_pulse = pulse_device_register(label, dev); 116 | if (!new_pulse) { 117 | fwnode_handle_put(child); 118 | ret = PTR_ERR(new_pulse); 119 | goto error; 120 | } 121 | 122 | /* Is GPIO in pin IRQ capable? */ 123 | irq = gpiod_to_irq(gpiod); 124 | if (irq < 0) { 125 | ret = irq; 126 | goto error; 127 | } 128 | 129 | /* Ok, now we can request the IRQ */ 130 | ret = request_irq(irq, (irq_handler_t) irq_handler, flags, 131 | PULSE_GPIO_NAME, new_pulse); 132 | if (ret < 0) 133 | goto error; 134 | 135 | priv->pulse[priv->num_pulses].dev = new_pulse; 136 | priv->pulse[priv->num_pulses].irq = irq; 137 | priv->num_pulses++; 138 | } 139 | 140 | platform_set_drvdata(pdev, priv); 141 | 142 | return 0; 143 | 144 | error: 145 | /* Unregister everything in case of errors */ 146 | for (count = priv->num_pulses - 1; count >= 0; count--) { 147 | if (priv->pulse[count].dev) 148 | pulse_device_unregister(priv->pulse[count].dev); 149 | if (priv->pulse[count].irq && priv->pulse[count].dev) 150 | free_irq(priv->pulse[count].irq, 151 | priv->pulse[count].dev); 152 | } 153 | 154 | return ret; 155 | } 156 | 157 | static int pulse_gpio_remove(struct platform_device *pdev) 158 | { 159 | struct pulse_gpio_priv *priv = platform_get_drvdata(pdev); 160 | int i; 161 | 162 | for (i = 0; i < priv->num_pulses; i++) { 163 | if (priv->pulse[i].dev) 164 | pulse_device_unregister(priv->pulse[i].dev); 165 | if (priv->pulse[i].irq && priv->pulse[i].dev) 166 | free_irq(priv->pulse[i].irq, 167 | priv->pulse[i].dev); 168 | } 169 | 170 | return 0; 171 | } 172 | 173 | static const struct of_device_id of_gpio_pulses_match[] = { 174 | { .compatible = "gpio-pulses", }, 175 | { /* sentinel */ } 176 | }; 177 | MODULE_DEVICE_TABLE(of, of_gpio_pulses_match); 178 | 179 | static struct platform_driver pulse_gpio_driver = { 180 | .probe = pulse_gpio_probe, 181 | .remove = pulse_gpio_remove, 182 | .driver = { 183 | .name = PULSE_GPIO_NAME, 184 | .of_match_table = of_gpio_pulses_match, 185 | }, 186 | }; 187 | 188 | module_platform_driver(pulse_gpio_driver); 189 | MODULE_AUTHOR("Rodolfo Giometti "); 190 | MODULE_DESCRIPTION("Pulse support for counting-board"); 191 | MODULE_LICENSE("GPL"); 192 | -------------------------------------------------------------------------------- /Chapter03/pulse/pulse-gpio_at91-sama5d3_xplained.dts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..83ff63b 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -332,5 +332,22 @@ 6 | label = "d3"; 7 | gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; 8 | }; 9 | + 10 | + }; 11 | + 12 | + pulses { 13 | + compatible = "gpio-pulses"; 14 | + 15 | + oil { 16 | + label = "oil"; 17 | + gpios = <&pioA 17 GPIO_ACTIVE_HIGH>; 18 | + trigger = "both"; 19 | + }; 20 | + 21 | + water { 22 | + label = "water"; 23 | + gpios = <&pioA 19 GPIO_ACTIVE_HIGH>; 24 | + trigger = "rising"; 25 | + }; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /Chapter03/pulse/pulse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pulse.h" 17 | 18 | #define DRIVER_NAME "pulse" 19 | #define DRIVER_VERSION "0.80.0" 20 | 21 | /* 22 | * Local variables 23 | */ 24 | 25 | static dev_t pulse_devt; 26 | static struct class *pulse_class; 27 | 28 | static DEFINE_MUTEX(pulse_idr_lock); 29 | static DEFINE_IDR(pulse_idr); 30 | 31 | /* 32 | * sysfs methods 33 | */ 34 | 35 | static ssize_t counter_show(struct device *dev, 36 | struct device_attribute *attr, char *buf) 37 | { 38 | struct pulse_device *pulse = dev_get_drvdata(dev); 39 | 40 | return sprintf(buf, "%d\n", atomic_read(&pulse->counter)); 41 | } 42 | static DEVICE_ATTR_RO(counter); 43 | 44 | static ssize_t counter_and_reset_show(struct device *dev, 45 | struct device_attribute *attr, char *buf) 46 | { 47 | struct pulse_device *pulse = dev_get_drvdata(dev); 48 | int counter = atomic_read(&pulse->counter); 49 | 50 | atomic_set(&pulse->counter, 0); 51 | return sprintf(buf, "%d\n", counter); 52 | } 53 | static DEVICE_ATTR_RO(counter_and_reset); 54 | 55 | static ssize_t set_to_store(struct device *dev, 56 | struct device_attribute *attr, 57 | const char *buf, size_t count) 58 | { 59 | struct pulse_device *pulse = dev_get_drvdata(dev); 60 | int status, ret; 61 | 62 | ret = sscanf(buf, "%d", &status); 63 | if (ret != 1) 64 | return -EINVAL; 65 | 66 | atomic_set(&pulse->counter, status); 67 | 68 | return count; 69 | } 70 | static DEVICE_ATTR_WO(set_to); 71 | 72 | /* 73 | * Class attributes 74 | */ 75 | 76 | static struct attribute *pulse_attrs[] = { 77 | &dev_attr_counter.attr, 78 | &dev_attr_counter_and_reset.attr, 79 | &dev_attr_set_to.attr, 80 | NULL, 81 | }; 82 | 83 | static const struct attribute_group pulse_group = { 84 | .attrs = pulse_attrs, 85 | }; 86 | 87 | static const struct attribute_group *pulse_groups[] = { 88 | &pulse_group, 89 | NULL, 90 | }; 91 | 92 | 93 | static void pulse_device_destruct(struct device *dev) 94 | { 95 | struct pulse_device *pulse = dev_get_drvdata(dev); 96 | 97 | /* Now we can release the ID for re-use */ 98 | pr_debug("deallocating pulse%d\n", pulse->id); 99 | mutex_lock(&pulse_idr_lock); 100 | idr_remove(&pulse_idr, pulse->id); 101 | mutex_unlock(&pulse_idr_lock); 102 | 103 | kfree(dev); 104 | kfree(pulse); 105 | } 106 | 107 | /* 108 | * Exported functions 109 | */ 110 | 111 | void pulse_event(struct pulse_device *pulse) 112 | { 113 | atomic_inc(&pulse->counter); 114 | } 115 | EXPORT_SYMBOL(pulse_event); 116 | 117 | struct pulse_device *pulse_device_register(const char *name, 118 | struct device *parent) 119 | { 120 | struct pulse_device *pulse; 121 | dev_t devt; 122 | int ret; 123 | 124 | /* First allocate a new pulse device */ 125 | pulse = kmalloc(sizeof(struct pulse_device), GFP_KERNEL); 126 | if (unlikely(!pulse)) 127 | return ERR_PTR(-ENOMEM); 128 | 129 | mutex_lock(&pulse_idr_lock); 130 | /* 131 | * Get new ID for the new pulse source. After idr_alloc() calling 132 | * the new source will be freely available into the kernel. 133 | */ 134 | ret = idr_alloc(&pulse_idr, pulse, 0, PULSE_MAX_SOURCES, GFP_KERNEL); 135 | if (ret < 0) { 136 | if (ret == -ENOSPC) { 137 | pr_err("%s: too many PPS sources in the system\n", 138 | name); 139 | ret = -EBUSY; 140 | } 141 | goto error_device_create; 142 | } 143 | pulse->id = ret; 144 | mutex_unlock(&pulse_idr_lock); 145 | 146 | devt = MKDEV(MAJOR(pulse_devt), pulse->id); 147 | 148 | /* Create the device and init the device's data */ 149 | pulse->dev = device_create(pulse_class, parent, devt, pulse, 150 | "%s", name); 151 | if (unlikely(IS_ERR(pulse->dev))) { 152 | dev_err(pulse->dev, "unable to create device %s\n", name); 153 | ret = PTR_ERR(pulse->dev); 154 | goto error_idr_remove; 155 | } 156 | dev_set_drvdata(pulse->dev, pulse); 157 | pulse->dev->release = pulse_device_destruct; 158 | 159 | /* Init the pulse data */ 160 | strncpy(pulse->name, name, PULSE_NAME_LEN); 161 | atomic_set(&pulse->counter, 0); 162 | pulse->old_status = -1; 163 | 164 | dev_info(pulse->dev, "pulse %s added\n", pulse->name); 165 | 166 | return pulse; 167 | 168 | error_idr_remove: 169 | mutex_lock(&pulse_idr_lock); 170 | idr_remove(&pulse_idr, pulse->id); 171 | 172 | error_device_create: 173 | mutex_unlock(&pulse_idr_lock); 174 | kfree(pulse); 175 | 176 | return ERR_PTR(ret); 177 | } 178 | EXPORT_SYMBOL(pulse_device_register); 179 | 180 | void pulse_device_unregister(struct pulse_device *pulse) 181 | { 182 | /* Drop all allocated resources */ 183 | device_destroy(pulse_class, pulse->dev->devt); 184 | 185 | dev_info(pulse->dev, "pulse %s removed\n", pulse->name); 186 | } 187 | EXPORT_SYMBOL(pulse_device_unregister); 188 | 189 | /* 190 | * Module stuff 191 | */ 192 | 193 | static int __init pulse_init(void) 194 | { 195 | printk(KERN_INFO "Pulse driver support v. " DRIVER_VERSION 196 | " - (C) 2014-2016 Rodolfo Giometti\n"); 197 | 198 | /* Create the new class */ 199 | pulse_class = class_create(THIS_MODULE, "pulse"); 200 | if (!pulse_class) { 201 | printk(KERN_ERR "pulse: failed to allocate class\n"); 202 | return -ENOMEM; 203 | } 204 | pulse_class->dev_groups = pulse_groups; 205 | 206 | return 0; 207 | } 208 | 209 | static void __exit pulse_exit(void) 210 | { 211 | class_destroy(pulse_class); 212 | } 213 | 214 | module_init(pulse_init); 215 | module_exit(pulse_exit); 216 | 217 | MODULE_AUTHOR("Rodolfo Giometti "); 218 | MODULE_DESCRIPTION("Pulse driver support v. " DRIVER_VERSION); 219 | MODULE_LICENSE("GPL"); 220 | MODULE_VERSION(DRIVER_VERSION); 221 | -------------------------------------------------------------------------------- /Chapter03/pulse/pulse.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PULSE_MAX_SOURCES 32 /* should be enough... */ 5 | #define PULSE_NAME_LEN 32 6 | 7 | /* 8 | * Pulse port basic structs 9 | */ 10 | 11 | /* Main struct */ 12 | struct pulse_device { 13 | char name[PULSE_NAME_LEN]; 14 | 15 | atomic_t counter; 16 | unsigned int old_status; 17 | 18 | unsigned int id; 19 | struct module *owner; 20 | struct device *dev; 21 | }; 22 | 23 | /* 24 | * Exported functions 25 | */ 26 | 27 | #define to_class_dev(obj) container_of((obj), struct class_device, kobj) 28 | #define to_pulse_device(obj) container_of((obj), struct pulse_device, class) 29 | 30 | extern void pulse_event(struct pulse_device *pulse); 31 | extern struct pulse_device *pulse_device_register(const char *name, 32 | struct device *parent); 33 | extern void pulse_device_unregister(struct pulse_device *pulse); 34 | -------------------------------------------------------------------------------- /Chapter03/pulse_gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=$(basename $0) 4 | declare -a valid_boards=(bbb a5d3) 5 | declare -a valid_gpios_bbb=(69 68 45 44 23 26 47 46 27 65) 6 | declare -a valid_gpios_a5d3=(A16) 7 | 8 | function usage() { 9 | echo "usage: $NAME bbb|a5d3 " >&2 10 | exit 1 11 | } 12 | 13 | # 14 | # Main 15 | # 16 | 17 | # Check the command line 18 | [ $# -lt 3 ] && usage 19 | board=$1 20 | gpio=$2 21 | hz=$3 22 | 23 | # Sanity checks for input values 24 | # 25 | # - valid boards are: bbb, a5d3 26 | case $board in 27 | bbb) 28 | declare -a valid_gpios=${valid_gpios_bbb[*]} 29 | ;; 30 | 31 | a5d3) 32 | declare -a valid_gpios=${valid_gpios_a5d3[*]} 33 | ;; 34 | esac 35 | # 36 | # - valid GPIOs are: 69, 68, 45, 44, 23, 26, 47, 46, 27, 65 37 | # - valid Hz values: [1:50] 38 | if ! [[ ${valid_gpios[*]} =~ $(echo "\<$gpio\>") ]] ; then 39 | echo "$NAME: GPIO # not allowed, must be in [${valid_gpios[*]}]" >&2 40 | exit 1 41 | fi 42 | if [ $hz -lt 1 -o $hz -gt 50 ] ; then 43 | echo "$NAME: invalid Hz value, must be in [1:50]" >&2 44 | exit 1 45 | fi 46 | 47 | # Convert GPIO name -> number 48 | case $board in 49 | bbb) 50 | num=$gpio 51 | name=gpio$gpio 52 | ;; 53 | 54 | a5d3) 55 | declare -A base 56 | base[A]=0 57 | port=${gpio:0:1} 58 | 59 | num=$(( ${gpio:1:2} + ${base[$port]} )) 60 | name=pio$gpio 61 | ;; 62 | esac 63 | 64 | # Export the GPIO and set it as output 65 | echo $num > /sys/class/gpio/export 66 | echo out > /sys/class/gpio/$name/direction 67 | 68 | # Start to generate the pulse 69 | # Period 1/Hz and duty cicle 50% 70 | echo "$NAME: start in generate the waveform. Hit ENTER key to stop" 71 | 72 | to=$(awk "BEGIN { print 1 / $hz / 2 }") ;# compute 1/hz/2 73 | while true ; do 74 | # Do the high pulse and the wait for the half period 75 | echo 1 > /sys/class/gpio/$name/value 76 | read -t $to val && break 77 | 78 | # Do the low pulse and the wait for the half period 79 | echo 0 > /sys/class/gpio/$name/value 80 | read -t $to val && break 81 | done 82 | 83 | # Unexport the GPIO 84 | echo $num > /sys/class/gpio/unexport 85 | 86 | exit 0 87 | -------------------------------------------------------------------------------- /Chapter04/README.md: -------------------------------------------------------------------------------- 1 | Chapter 4 - Quick Programming with scripts & system daemons 2 | =========================================================== 3 | 4 | Here the code from chapter 4 - "Quick Programming with scripts & system daemons" 5 | of the book "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some configuration and usage examples of the most famous UNIX's 9 | daemons presented into the book. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter04/mydaemon/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = mydaemon 2 | 3 | CFLAGS = -Wall -O2 -D_GNU_SOURCE 4 | 5 | all : $(TARGET) 6 | 7 | clean : 8 | rm -rf $(TARGET) 9 | -------------------------------------------------------------------------------- /Chapter04/mydaemon/mydaemon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define NAME program_invocation_short_name 11 | 12 | int debug = 0; 13 | int daemonize = 1; 14 | int logstderr = 0; 15 | 16 | /* 17 | * Logging functions 18 | */ 19 | 20 | #define dbg(fmt, args...) \ 21 | do { \ 22 | if (debug) \ 23 | syslog(LOG_DEBUG, fmt , ## args); \ 24 | } while (0) 25 | 26 | #define info(fmt, args...) \ 27 | syslog(LOG_INFO, fmt , ## args) 28 | 29 | /* 30 | * Signals handler 31 | */ 32 | 33 | void sig_handler(int signo) 34 | { 35 | dbg("signal trapped!"); 36 | exit(0); 37 | } 38 | 39 | /* 40 | * The daemon body 41 | */ 42 | 43 | void daemon_body(void) 44 | { 45 | /* The main loop */ 46 | dbg("start main loop"); 47 | while (sleep(1) == 0) 48 | info("I'm working hard!"); 49 | } 50 | 51 | /* 52 | * Usage function 53 | */ 54 | 55 | void usage(void) 56 | { 57 | fprintf(stderr, "usage: %s [-h] [-d] [-f] [-l]\n", NAME); 58 | fprintf(stderr, " -h - show this message\n"); 59 | fprintf(stderr, " -d - enable debugging messages\n"); 60 | fprintf(stderr, " -f - do not daemonize\n"); 61 | fprintf(stderr, " -l - log on stderr\n"); 62 | 63 | exit(-1); 64 | } 65 | 66 | /* 67 | * Main 68 | */ 69 | 70 | int main(int argc, char *argv[]) 71 | { 72 | int c, option_index; 73 | int loglevel; 74 | sighandler_t sig_h; 75 | int ret; 76 | 77 | opterr = 0; /* disbale default error message */ 78 | while (1) { 79 | /* getopt_long stores the option index here */ 80 | option_index = 0; 81 | 82 | c = getopt_long(argc, argv, "hdfl", NULL, &option_index); 83 | 84 | /* Detect the end of the options */ 85 | if (c == -1) 86 | break; 87 | 88 | switch (c) { 89 | case 0: 90 | break; 91 | 92 | case 'h': 93 | usage(); 94 | 95 | case 'd': 96 | debug = 1; 97 | break; 98 | 99 | case 'f': 100 | daemonize = 0; 101 | break; 102 | 103 | case 'l': 104 | logstderr = 1; 105 | break; 106 | 107 | case '?': 108 | fprintf(stderr, "unhandled option"); 109 | exit(-1); 110 | 111 | default: 112 | exit(-1); 113 | } 114 | } 115 | 116 | /* Open the communication with syslogd */ 117 | loglevel = LOG_PID; 118 | if (logstderr) 119 | loglevel |= LOG_PERROR; 120 | openlog(NAME, loglevel, LOG_USER); 121 | 122 | /* Install the signals traps */ 123 | sig_h = signal(SIGTERM, sig_handler); 124 | if (sig_h == SIG_ERR) { 125 | fprintf(stderr, "unable to catch SIGTERM"); 126 | exit(-1); 127 | } 128 | sig_h = signal(SIGINT, sig_handler); 129 | if (sig_h == SIG_ERR) { 130 | fprintf(stderr, "unable to catch SIGINT"); 131 | exit(-1); 132 | } 133 | dbg("signals traps installed"); 134 | 135 | /* Should run as a daemon? */ 136 | if (daemonize) { 137 | ret = daemon(!daemonize, 1); 138 | if (ret) { 139 | fprintf(stderr, "unable to daemonize the process"); 140 | exit(-1); 141 | } 142 | } 143 | 144 | daemon_body(); 145 | 146 | return 0; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /Chapter04/mydaemon/mydaemon.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $a) { 79 | switch ($o) { 80 | case "h": 81 | usage(); 82 | 83 | case "d": 84 | $debug = true; 85 | $nopts++; 86 | break; 87 | 88 | case "f": 89 | $daemonize = false; 90 | $nopts++; 91 | break; 92 | 93 | case "l": 94 | $logstderr = true; 95 | $nopts++; 96 | break; 97 | } 98 | } 99 | 100 | # Open the communication with syslogd 101 | $loglevel = LOG_PID; 102 | if ($logstderr) 103 | $loglevel |= LOG_PERROR; 104 | openlog(NAME, $loglevel, LOG_USER); 105 | 106 | # Install the signals traps 107 | pcntl_signal(SIGTERM, "sig_handler"); 108 | pcntl_signal(SIGINT, "sig_handler"); 109 | dbg("signals traps installed"); 110 | 111 | # Start the daemon 112 | if ($daemonize) { 113 | dbg("going in background..."); 114 | $pid = pcntl_fork(); 115 | if ($pid < 0) { 116 | die("unable to daemonize!"); 117 | } 118 | if ($pid) { 119 | # The parent can exit... 120 | exit(0); 121 | } 122 | # ... while the children goes on! 123 | 124 | # Set the working directory to / 125 | chdir("/"); 126 | 127 | # Close all of the standard file descriptors as we are running 128 | # as a daemon 129 | fclose(STDIN); 130 | fclose(STDOUT); 131 | fclose(STDERR); 132 | } 133 | 134 | daemon_body(); 135 | 136 | exit(0); 137 | -------------------------------------------------------------------------------- /Chapter04/mydaemon/mydaemon.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import time 7 | import getopt 8 | import syslog 9 | import signal 10 | import daemon 11 | 12 | NAME = os.path.basename(sys.argv[0]) 13 | 14 | debug = False 15 | daemonize = True 16 | logstderr = False 17 | 18 | # 19 | # Logging functions 20 | # 21 | 22 | def dbg(x): 23 | if not debug: 24 | return 25 | 26 | syslog.syslog(syslog.LOG_DEBUG, str(x)) 27 | 28 | def info(x): 29 | syslog.syslog(syslog.LOG_INFO, str(x)) 30 | 31 | # 32 | # Signals handler 33 | # 34 | 35 | def sig_handler(sig, frame): 36 | dbg("signal trapped!") 37 | sys.exit(0) 38 | 39 | # 40 | # The daemon body 41 | # 42 | 43 | def daemon_body(): 44 | # The main loop 45 | dbg("start main loop") 46 | while not time.sleep(1): 47 | info("I\'m working hard!") 48 | 49 | # 50 | # Usage 51 | # 52 | 53 | def usage(): 54 | print("usage: ", NAME, " [-h] [-d] [-f] [-l]", file = sys.stderr) 55 | print(" -h - show this message", file = sys.stderr) 56 | print(" -d - enable debugging messages", file = sys.stderr) 57 | print(" -f - do not daemonize", file = sys.stderr) 58 | print(" -l - log on stderr", file = sys.stderr) 59 | 60 | sys.exit(1) 61 | 62 | # 63 | # Main 64 | # 65 | 66 | # Check the command line 67 | try: 68 | opts, args = getopt.getopt(sys.argv[1:], "hdfl") 69 | except getopt.GetoptError, err: 70 | print(str(err), file = sys.stderr) 71 | usage() 72 | 73 | for o, a in opts: 74 | if o in ("-h"): 75 | usage() 76 | elif o in ("-d"): 77 | debug = True 78 | elif o in ("-f"): 79 | daemonize = False 80 | elif o in ("-l"): 81 | logstderr = True 82 | else: 83 | assert False, "unhandled option" 84 | 85 | # Open the communication with syslogd 86 | loglevel = syslog.LOG_PID 87 | if logstderr: 88 | loglevel |= syslog.LOG_PERROR 89 | syslog.openlog(NAME, loglevel, syslog.LOG_USER) 90 | 91 | # Define the daemon context and install the signals traps 92 | context = daemon.DaemonContext( 93 | detach_process = daemonize, 94 | ) 95 | context.signal_map = { 96 | signal.SIGTERM: sig_handler, 97 | signal.SIGINT: sig_handler, 98 | } 99 | dbg("signals traps installed") 100 | 101 | # Start the daemon 102 | with context: 103 | daemon_body() 104 | 105 | sys.exit(0) 106 | -------------------------------------------------------------------------------- /Chapter04/mydaemon/mydaemon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=$(basename $0) 4 | 5 | daemonize="&" 6 | 7 | # 8 | # Logging functions 9 | # 10 | 11 | function dbg () { 12 | [ $debug ] && logger -p user.debug -t $NAME $logstderr $1 13 | } 14 | 15 | function info () { 16 | logger -p user.info -t $NAME $logstderr $1 17 | } 18 | 19 | # 20 | # Signals handler 21 | # 22 | 23 | function sig_handler () { 24 | dbg "signal trapped!" 25 | exit 0 26 | } 27 | 28 | # 29 | # The daemon body 30 | # 31 | 32 | function daemon_body () { 33 | # The main loop 34 | dbg "start main loop" 35 | while sleep 1 ; do 36 | info "I'm working hard!" 37 | done 38 | } 39 | 40 | # 41 | # Usage 42 | # 43 | 44 | function usage () { 45 | echo "usage: $NAME [-h] [-d] [-f] [-l]" >&2 46 | echo " -h - show this message" >&2 47 | echo " -d - enable debugging messages" >&2 48 | echo " -f - do not daemonize" >&2 49 | echo " -l - log on stderr" >&2 50 | 51 | exit 1 52 | } 53 | 54 | # 55 | # Main 56 | # 57 | 58 | # Check the command line 59 | TEMP=$(getopt -o hdfl -n $NAME -- "$@") 60 | [ $? != 0 ] && exit 1 61 | eval set -- "$TEMP" 62 | while true ; do 63 | case "$1" in 64 | -h) 65 | usage 66 | ;; 67 | 68 | -d) 69 | debug="true" 70 | shift 71 | ;; 72 | 73 | -f) 74 | daemonize="" 75 | shift 76 | ;; 77 | 78 | -l) 79 | logstderr="--stderr" 80 | shift 81 | ;; 82 | 83 | --) 84 | shift 85 | break 86 | ;; 87 | 88 | *) 89 | echo "$NAME: internal error!" >&2 90 | exit 1 91 | ;; 92 | esac 93 | done 94 | 95 | # Install the signals traps 96 | trap sig_handler SIGTERM SIGINT 97 | dbg "signals traps installed" 98 | 99 | # Start the daemon 100 | if [ -n "$daemonize" ] ; then 101 | dbg "going in background..." 102 | 103 | # Set the working directory to / 104 | cd / 105 | fi 106 | [ -z "$logstderr" ] && tmp="2>&1" 107 | eval daemon_body /dev/null $tmp $daemonize 108 | 109 | exit 0 110 | -------------------------------------------------------------------------------- /Chapter04/mysql/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS = my_set my_dump 2 | 3 | CFLAGS = -Wall -O2 -D_GNU_SOURCE -I/usr/include/mysql 4 | LDLIBS = -lmysqlclient 5 | 6 | all : $(TARGETS) 7 | 8 | clean : 9 | rm -rf $(TARGETS) 10 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NAME program_invocation_short_name 14 | 15 | void usage(void) 16 | { 17 | fprintf(stderr, "usage: %s \n", NAME); 18 | 19 | exit(-1); 20 | } 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | const char *query = "SELECT * FROM status;"; 25 | MYSQL *c; 26 | MYSQL_RES *q_res; 27 | MYSQL_FIELD *field; 28 | MYSQL_ROW row; 29 | int i, n; 30 | int ret = 0; 31 | 32 | /* Get connect to MySQL daemon */ 33 | c = mysql_init(NULL); 34 | if (!c) { 35 | fprintf(stderr, "unable to init MySQL data struct\n"); 36 | return -1; 37 | } 38 | 39 | if (!mysql_real_connect(c, "127.0.0.1", "user", "userpass", 40 | "sproject", 0, NULL, 0)) { 41 | fprintf(stderr, "unable to connect to MySQL daemon\n"); 42 | ret = -1; 43 | goto close_db; 44 | } 45 | 46 | /* Ok, do the job! */ 47 | ret = mysql_query(c, query); 48 | if (ret < 0) 49 | fprintf(stderr, "unable to access the database\n"); 50 | 51 | /* Save the query result */ 52 | q_res = mysql_store_result(c); 53 | if (!q_res) { 54 | fprintf(stderr, "unable to store query result\n"); 55 | goto close_db; 56 | } 57 | 58 | /* Do the dump of the fields' names */ 59 | while ((field = mysql_fetch_field(q_res))) 60 | printf("%s\t", field->name); 61 | printf("\n"); 62 | 63 | /* Do the dump one line at time */ 64 | n = mysql_num_fields(q_res); 65 | while ((row = mysql_fetch_row(q_res))) { 66 | for (i = 0; i < n; i++) 67 | printf("%s\t", row[i] ? row[i] : NULL); 68 | printf("\n"); 69 | } 70 | 71 | mysql_free_result(q_res); 72 | close_db: 73 | mysql_close(c); 74 | 75 | return ret; 76 | } 77 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_dump.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | 35 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import MySQLdb 4 | 5 | # Get connect to MySQL daemon 6 | db = MySQLdb.connect(host = "localhost", user = "user", passwd = "userpass", 7 | db = "sproject") 8 | 9 | # Create the Cursor object to execute all queries 10 | c = db.cursor() 11 | 12 | # Ok, do the job! 13 | c.execute("SELECT * FROM status") 14 | 15 | # Save the query result 16 | data = c.fetchall() 17 | 18 | # Do the dump of the fields' names 19 | for field in c.description: 20 | print("%s\t" % (field[0])), 21 | print 22 | 23 | # Do the dump one line at time 24 | n = len(c.description) 25 | for row in data: 26 | for i in range(0, n): 27 | print("%s\t" % (row[i])), 28 | print 29 | 30 | c.close() 31 | db.close() 32 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=$(basename $0) 4 | 5 | PASSWD="userpass" 6 | 7 | # Ok, do the job! 8 | mysql -u user --password=$PASSWD -D sproject <<__EOF__ 9 | 10 | # Do the whole dump 11 | SELECT * FROM status; 12 | 13 | __EOF__ 14 | 15 | exit 0 16 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=$(basename $0) 4 | 5 | echo -n "Warning, all data will be dropped!!! [CTRL-C to stop or ENTER to continue]" 6 | read ans 7 | 8 | # Ok, do the job! 9 | mysql -u root -p <<__EOF__ 10 | 11 | # Drop all existing data!!! 12 | DROP DATABASE IF EXISTS sproject; 13 | 14 | # Create new database 15 | CREATE DATABASE sproject; 16 | 17 | # Grant privileges 18 | GRANT USAGE ON *.* TO user@localhost IDENTIFIED BY 'userpass'; 19 | GRANT ALL PRIVILEGES ON sproject.* TO user@localhost; 20 | FLUSH PRIVILEGES; 21 | 22 | # Select database 23 | USE sproject; 24 | 25 | # Create the statuses table 26 | CREATE TABLE status ( 27 | t DATETIME NOT NULL, 28 | n VARCHAR(64) NOT NULL, 29 | v VARCHAR(64) NOT NULL, 30 | PRIMARY KEY (n), 31 | INDEX (n) 32 | ) ENGINE=MEMORY; 33 | 34 | __EOF__ 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NAME program_invocation_short_name 14 | 15 | void usage(void) 16 | { 17 | fprintf(stderr, "usage: %s \n", NAME); 18 | 19 | exit(-1); 20 | } 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | const char *query = "REPLACE INTO status (t, n, v) " 25 | "VALUES(now(), '%s', '%s');"; 26 | char *name, *value; 27 | MYSQL *c; 28 | char *sql; 29 | int ret = 0; 30 | 31 | /* Check the command line */ 32 | if (argc < 3) 33 | usage(); 34 | name = argv[1]; 35 | value = argv[2]; 36 | 37 | /* Get connect to MySQL daemon */ 38 | c = mysql_init(NULL); 39 | if (!c) { 40 | fprintf(stderr, "unable to init MySQL data struct\n"); 41 | return -1; 42 | } 43 | 44 | if (!mysql_real_connect(c, "127.0.0.1", "user", "userpass", 45 | "sproject", 0, NULL, 0)) { 46 | fprintf(stderr, "unable to connect to MySQL daemon\n"); 47 | ret = -1; 48 | goto close_db; 49 | } 50 | 51 | /* Ok, do the job! */ 52 | ret = asprintf(&sql, query, name, value); 53 | if (ret < 0) { 54 | fprintf(stderr, "unable to allocate memory for query\n"); 55 | goto close_db; 56 | } 57 | 58 | ret = mysql_query(c, sql); 59 | if (ret < 0) 60 | fprintf(stderr, "unable to access the database\n"); 61 | 62 | free(sql); 63 | close_db: 64 | mysql_close(c); 65 | 66 | return ret; 67 | } 68 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_set.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | \n"); 7 | } 8 | 9 | /* Check the command line */ 10 | if ($argc < 3) 11 | usage($argv[0]); 12 | $name = $argv[1]; 13 | $value = $argv[2]; 14 | 15 | # Get connect to MySQL daemon 16 | $ret = mysql_connect("127.0.0.1", "user", "userpass"); 17 | if (!$ret) 18 | die("unable to connect with MySQL daemon"); 19 | 20 | $ret = mysql_select_db("sproject"); 21 | if (!$ret) 22 | die("unable to select database"); 23 | 24 | # Ok, do the job! 25 | $query = "REPLACE INTO status (t, n, v) " . 26 | "VALUES(now(), '$name', '$value');"; 27 | $dbres = mysql_query($query); 28 | if (!$dbres) 29 | die("unable to execute the query"); 30 | 31 | mysql_close(); 32 | 33 | ?> 34 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_set.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import MySQLdb 7 | 8 | NAME = os.path.basename(sys.argv[0]) 9 | 10 | def usage(): 11 | print("usage: ", NAME, " ", file = sys.stderr) 12 | sys.exit(2); 13 | 14 | # Check the command line 15 | if len(sys.argv) < 3: 16 | usage() 17 | 18 | # Get connect to MySQL daemon 19 | db = MySQLdb.connect(host = "localhost", user = "user", passwd = "userpass", 20 | db = "sproject") 21 | 22 | # Create the Cursor object to execute all queries 23 | c = db.cursor() 24 | 25 | # Ok, do the job! 26 | query = "REPLACE INTO status (t, n, v) " \ 27 | "VALUES(now(), '%s', '%s');" % (sys.argv[1], sys.argv[2]) 28 | c.execute(query) 29 | 30 | 31 | c.close() 32 | db.close() 33 | -------------------------------------------------------------------------------- /Chapter04/mysql/my_set.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=$(basename $0) 4 | 5 | PASSWD="userpass" 6 | 7 | usage() { 8 | echo "usage: $NAME " >&2 9 | exit 1 10 | } 11 | 12 | [ $# -lt 2 ] && usage 13 | name=$1 14 | value=$2 15 | 16 | # Ok, do the job! 17 | mysql -u user --password=$PASSWD -D sproject <<__EOF__ 18 | 19 | REPLACE INTO status (t, n, v) VALUES(now(), '$name', '$value'); 20 | 21 | __EOF__ 22 | 23 | exit 0 24 | -------------------------------------------------------------------------------- /Chapter04/syslogd/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = logger 2 | 3 | CFLAGS = -Wall -O2 4 | 5 | all : $(TARGET) 6 | 7 | clean : 8 | rm -rf $(TARGET) 9 | -------------------------------------------------------------------------------- /Chapter04/syslogd/logger.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | openlog("mydaemon", LOG_NOWAIT, LOG_USER); 6 | 7 | syslog(LOG_INFO, "logging message in C"); 8 | 9 | closelog(); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter04/syslogd/logger.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /Chapter04/syslogd/logger.py: -------------------------------------------------------------------------------- 1 | import syslog 2 | 3 | syslog.openlog("mydaemon", syslog.LOG_NOWAIT, syslog.LOG_USER) 4 | 5 | syslog.syslog(syslog.LOG_INFO, "logging message in Python") 6 | 7 | syslog.closelog() 8 | -------------------------------------------------------------------------------- /Chapter04/webled/bash/httpd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The server's root directory 4 | base=/var/www/html 5 | 6 | # Read the browser request 7 | read request 8 | 9 | # Now read the message header 10 | while /bin/true; do 11 | read header 12 | [ "$header" == $'\r' ] && break; 13 | done 14 | 15 | # Parse the GET request 16 | tmp="${request#GET }" 17 | tmp="${tmp% HTTP/*}" 18 | 19 | # Extract the code after the '?' char to capture a variable setting 20 | var="${tmp#*\?}" 21 | [ "$var" == "$tmp" ] && var="" 22 | 23 | # Get the URL and replace it with "/index.html" in case it is set to "/" 24 | url="${tmp%\?*}" 25 | [ "$url" == "/" ] && url="/index.html" 26 | 27 | # Extract the filename 28 | filename="$base$url" 29 | extension="${filename##*.}" 30 | 31 | # Check for file exist 32 | if [ -f "$filename" ]; then 33 | echo -e "HTTP/1.1 200 OK\r" 34 | echo -e "Contant-type: text/html\r" 35 | echo -e "\r" 36 | 37 | # If file's extension is "cgi" and it's executable the execute it, 38 | # otherwise just return its contents 39 | if [ "$extension" == "cgi" -a -x "$filename" ]; then 40 | $filename $var 41 | else 42 | cat "$filename" 43 | fi 44 | echo -e "\r" 45 | else 46 | # If the file does not exist return an error 47 | echo -e "HTTP/1.1 404 Not Found\r" 48 | echo -e "Content-Type: text/html\r" 49 | echo -e "\r" 50 | echo -e "404 Not Found\r" 51 | echo -e "The requested resource was not found\r" 52 | echo -e "\r" 53 | fi 54 | 55 | exit 0 56 | -------------------------------------------------------------------------------- /Chapter04/webled/bash/httpd_echo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Read the browser request 4 | read request 5 | 6 | # Now read the message header 7 | while /bin/true; do 8 | read header 9 | echo "$header" 10 | [ "$header" == $'\r' ] && break; 11 | done 12 | 13 | # And then produce an answer with a message dump 14 | echo -e "HTTP/1.1 200 OK\r" 15 | echo -e "Content-type: text/html\r" 16 | echo -e "\r" 17 | 18 | echo -e "request=$request\r" 19 | 20 | exit 0 21 | -------------------------------------------------------------------------------- /Chapter04/webled/bash/httpd_sh: -------------------------------------------------------------------------------- 1 | service http-alt 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | server = /root/httpd.sh 9 | } 10 | -------------------------------------------------------------------------------- /Chapter04/webled/bash/turn.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 1st part - Global defines & functions 4 | value_f="/sys/class/gpio/gpio66/value" 5 | 6 | function pr_str ( ) { 7 | [ $1 == 1 ] && echo "on" 8 | [ $1 == 0 ] && echo "off" 9 | } 10 | 11 | # 2nd part - Set the new led status as requested 12 | if [ -n "$1" ] ; then 13 | eval $1 ;# this evaluate the query 'led=0' 14 | led_new_status=$led 15 | echo $led_new_status > $value_f 16 | fi 17 | 18 | led_status=$(cat $value_f) 19 | 20 | led_new_status=$((1 - $led_status)) 21 | 22 | cat < 24 | 25 | Turing a led on/off using BASH 26 | 27 | 28 | 29 |

Turing a led on/off using BASH

30 | Current led status is: $(pr_str $led_status) 31 |

32 | 33 | Press the button to turn the led $(pr_str $led_new_status) 34 |

35 | 36 |

37 | 38 |
39 | 40 | 41 | EOF 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /Chapter04/webled/php/turn.php: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | Turning a led on/off using PHP 27 | 28 | 29 | 30 |

Turning a led on/off using PHP

31 | Current led status is: 32 |

33 | 34 | Press the button to turn the led 35 |

36 | 37 |

38 | 40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Chapter04/webled/python/httpd.py: -------------------------------------------------------------------------------- 1 | from BaseHTTPServer import BaseHTTPRequestHandler 2 | import urlparse 3 | 4 | # 1st part - Global defines & functions 5 | value_f = "/sys/class/gpio/gpio66/value" 6 | addr = ('192.168.7.2', 8080) 7 | 8 | def pr_str(val): 9 | return "on" if val else "off" 10 | 11 | def put_data(file, data): 12 | f = open(file, "w") 13 | f.write(data) 14 | f.close() 15 | 16 | def get_data(file): 17 | f = open(file, "r") 18 | data = f.read() 19 | f.close() 20 | return data 21 | 22 | class GetHandler(BaseHTTPRequestHandler): 23 | # 2nd part - Define the HTTPServer's GET handler 24 | def do_GET(self): 25 | parsed_path = urlparse.urlparse(self.path) 26 | 27 | # 1st part - Set the new led status as requested 28 | query = parsed_path.query 29 | data = urlparse.parse_qs(query) 30 | if ("led" in data): 31 | led_new_status = data["led"][0] 32 | put_data(value_f, led_new_status) 33 | 34 | # 3rd part - Get the current led status 35 | led_status = int(get_data(value_f)) 36 | 37 | # 4th part - Get the current led status 38 | led_new_status = 1 - led_status 39 | 40 | # 5th part - Get the current led status 41 | message = ''' 42 | 43 | 44 | Turing a led on/off using Python 45 | 46 | 47 | 48 |

Turing a led on/off using Python

49 | Current led status is: %s 50 |

51 | 52 | Press the button to turn the led %s 53 |

54 | 55 |

56 | 57 |
58 | 59 | 60 | ''' % (pr_str(led_status), pr_str(led_new_status), 61 | led_new_status, pr_str(led_new_status)) 62 | # 6th part - Send the answer 63 | self.send_response(200) 64 | self.end_headers() 65 | self.wfile.write(message) 66 | 67 | return 68 | 69 | # 7th part - Setup the web server 70 | if __name__ == '__main__': 71 | from BaseHTTPServer import HTTPServer 72 | server = HTTPServer(addr, GetHandler) 73 | print 'Starting server at %s:%s, use to stop' % addr 74 | server.serve_forever() 75 | -------------------------------------------------------------------------------- /Chapter04/webled/python/httpd_show_info.py: -------------------------------------------------------------------------------- 1 | from BaseHTTPServer import BaseHTTPRequestHandler 2 | import urlparse 3 | 4 | # 1st part - Global defines & functions 5 | addr = ('192.168.7.2', 8080) 6 | 7 | class GetHandler(BaseHTTPRequestHandler): 8 | # 2nd part - Define the HTTPServer's GET handler 9 | 10 | def do_GET(self): 11 | parsed_path = urlparse.urlparse(self.path) 12 | 13 | # 3rd part - Build the answering message 14 | message_parts = [ 15 | 'CLIENT VALUES', 16 | 'client_address -> %s (%s)' % (self.client_address, 17 | self.address_string()), 18 | 'command -> %s' % self.command, 19 | 'path -> %s' % self.path, 20 | 'real path -> t%s' % parsed_path.path, 21 | 'query -> %s' % parsed_path.query, 22 | 'request_version -> %s' % self.request_version, 23 | '', 24 | 'SERVER VALUES', 25 | 'server_version -> %s' % self.server_version, 26 | 'sys_version -> %s' % self.sys_version, 27 | 'protocol_version -> %s' % self.protocol_version, 28 | '', 29 | 'HEADERS RECEIVED', 30 | ] 31 | 32 | for name, value in sorted(self.headers.items()): 33 | message_parts.append('%s -> %s' % (name, 34 | value.rstrip())) 35 | message_parts.append('') 36 | message = '\r\n'.join(message_parts) 37 | 38 | # 4th part - Send the answer 39 | self.send_response(200) 40 | self.end_headers() 41 | self.wfile.write(message) 42 | 43 | return 44 | 45 | # 5th part - Setup the web server 46 | if __name__ == '__main__': 47 | from BaseHTTPServer import HTTPServer 48 | server = HTTPServer(addr, GetHandler) 49 | print 'Starting server at %s:%s, use to stop' % addr 50 | server.serve_forever() 51 | -------------------------------------------------------------------------------- /Chapter04/xinetd/echo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while /bin/true; do 4 | read line 5 | 6 | line=$(echo $line | tr -d '\n\r') 7 | [ "$line" == "quit" ] && break; 8 | 9 | echo -e "$line\r" 10 | done 11 | 12 | exit 0 13 | -------------------------------------------------------------------------------- /Chapter04/xinetd/echo_sh: -------------------------------------------------------------------------------- 1 | service at-echo 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | server = /root/echo.sh 9 | } 10 | -------------------------------------------------------------------------------- /Chapter05/README.md: -------------------------------------------------------------------------------- 1 | Chapter 5 - Setting up an embedded OS 2 | ===================================== 3 | 4 | Here the code from chapter 5 - "Setting up an embedded OS" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are two examples regarding Yocto and OpenWRT packages management. 9 | 10 | See the URL 11 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 12 | for further info. 13 | -------------------------------------------------------------------------------- /Chapter05/openwrt-helloworld/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | # Define package's name, version, release and the default package's 4 | # build directory. 5 | PKG_NAME:=helloworld 6 | PKG_VERSION:=1.0.0 7 | PKG_RELEASE:=1 8 | PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) 9 | 10 | include $(INCLUDE_DIR)/package.mk 11 | 12 | # Define package's section and category inside the OpenWRT system. 13 | # These information are used to manage the package and to display 14 | # it inside the comfiguration menu 15 | define Package/$(PKG_NAME) 16 | SECTION:=apps 17 | CATEGORY:=Applications 18 | TITLE:=The Hello World program 19 | MAINTAINER:=Rodolfo Giometti 20 | endef 21 | 22 | # Define package's description (long version) 23 | define Package/$(PKG_NAME)/description 24 | This package holds a program that display the "hello world" message 25 | endef 26 | 27 | # Set up the build directory in order to be use by the compilation 28 | # stage. 29 | # Our data are not downloaded from a remote site by we have them 30 | # already into the "src" directory, so let's copy them accordingly 31 | define Build/Prepare 32 | mkdir -p $(PKG_BUILD_DIR) 33 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 34 | endef 35 | 36 | # Define the package's installation steps after the compilation 37 | # stage has done 38 | define Package/$(PKG_NAME)/install 39 | $(INSTALL_DIR) $(1)/usr/bin 40 | $(CP) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin 41 | endef 42 | 43 | # The OpenWRT's main entry 44 | $(eval $(call BuildPackage,$(PKG_NAME))) 45 | -------------------------------------------------------------------------------- /Chapter05/openwrt-helloworld/src/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = helloworld 2 | 3 | all: $(TARGET) 4 | 5 | clean: 6 | rm *.o helloworld 7 | -------------------------------------------------------------------------------- /Chapter05/openwrt-helloworld/src/helloworld.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | printf("Hello World\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /Chapter05/phpdemo/demo_dump.php: -------------------------------------------------------------------------------- 1 |

OpenWRT PHP demo

2 | 3 | 4 | \n"; 20 | $hdrrow = mysqli_fetch_assoc($dbres); 21 | echo " \n"; 22 | foreach ($hdrrow as $hdr => $value) 23 | echo " \n"; 24 | echo "\n"; 25 | 26 | # Seek to row 0 27 | mysqli_data_seek($dbres, 0); 28 | 29 | # Do the dump one line at time 30 | while ($row = mysqli_fetch_assoc($dbres)) { 31 | echo " \n"; 32 | foreach ($row as $cell) 33 | echo ""; 34 | echo " \n"; 35 | } 36 | 37 | mysqli_close($conn); 38 | 39 | ?> 40 |
$hdr
$cell
41 | -------------------------------------------------------------------------------- /Chapter05/phpdemo/demo_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=$(basename $0) 4 | 5 | echo -n "Warning, all data will be dropped!!! [CTRL-C to stop or ENTER to continue]" 6 | read ans 7 | 8 | # Ok, do the job! 9 | mysql -u root -p <<__EOF__ 10 | 11 | # Drop all existing data!!! 12 | DROP DATABASE IF EXISTS phpdemo; 13 | 14 | # Create new database 15 | CREATE DATABASE phpdemo; 16 | 17 | # Grant privileges 18 | GRANT USAGE ON *.* TO user@localhost IDENTIFIED BY 'userpass'; 19 | GRANT ALL PRIVILEGES ON phpdemo.* TO user@localhost; 20 | FLUSH PRIVILEGES; 21 | 22 | # Select database 23 | USE phpdemo; 24 | 25 | # Create the statuses table 26 | CREATE TABLE status ( 27 | t DATETIME NOT NULL, 28 | n VARCHAR(64) NOT NULL, 29 | v VARCHAR(64) NOT NULL, 30 | PRIMARY KEY (n), 31 | INDEX (n) 32 | ) ENGINE=MEMORY; 33 | 34 | __EOF__ 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /Chapter05/phpdemo/demo_set.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=$(basename $0) 4 | 5 | PASSWD="userpass" 6 | 7 | usage() { 8 | echo "usage: $NAME " >&2 9 | exit 1 10 | } 11 | 12 | [ $# -lt 2 ] && usage 13 | name=$1 14 | value=$2 15 | 16 | # Ok, do the job! 17 | mysql -u user --password=$PASSWD -D phpdemo <<__EOF__ 18 | 19 | REPLACE INTO status (t, n, v) VALUES(now(), '$name', '$value'); 20 | 21 | __EOF__ 22 | 23 | exit 0 24 | -------------------------------------------------------------------------------- /Chapter06/BB-LEDS-C6-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-LEDS-C6-00A0"; 9 | 10 | /* The version */ 11 | version = "00A0"; 12 | 13 | /* Define the pins usage */ 14 | exclusive-use = 15 | /* the pin header P8 uses */ 16 | "P8.9", 17 | "P8.10", 18 | /* Hardware IP cores in use */ 19 | "timer5", 20 | "timer6"; 21 | 22 | fragment@0 { 23 | target = <&am33xx_pinmux>; 24 | 25 | __overlay__ { 26 | bb_led_pins: pinmux_bb_led_pins { 27 | pinctrl-single,pins = < 28 | 0x9c 0x37 29 | 0x98 0x37 30 | >; 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | 38 | __overlay__ { 39 | c6_leds { 40 | compatible = "gpio-leds"; 41 | pinctrl-names = "default"; 42 | pinctrl-0 = <&bb_led_pins>; 43 | 44 | yellow_led { 45 | label = "c6:yellow"; 46 | gpios = <&gpio2 5 0>; 47 | linux,default-trigger = "none"; 48 | default-state = "off"; 49 | }; 50 | 51 | red_led { 52 | label = "c6:red"; 53 | gpios = <&gpio2 4 0>; 54 | linux,default-trigger = "none"; 55 | default-state = "off"; 56 | }; 57 | 58 | }; 59 | }; 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /Chapter06/README.md: -------------------------------------------------------------------------------- 1 | Chapter 6 - General Purposes Input Output signals - GPIO 2 | ======================================================== 3 | 4 | Here the code from chapter 2 - "General Purposes Input Output signals - GPIO" 5 | of the book "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some example of GPIOs management from both kernel and user-space. 9 | 10 | See the URL 11 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 12 | for further info. 13 | -------------------------------------------------------------------------------- /Chapter06/gpio-irq/Makefile: -------------------------------------------------------------------------------- 1 | ifndef KERNEL_DIR 2 | $(error KERNEL_DIR must be set in the command line) 3 | endif 4 | PWD := $(shell pwd) 5 | CROSS_COMPILE = arm-linux-gnueabihf- 6 | 7 | obj-m = gpio-irq.o 8 | 9 | all: modules 10 | 11 | modules clean: 12 | $(MAKE) -C $(KERNEL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) \ 13 | SUBDIRS=$(PWD) $@ 14 | -------------------------------------------------------------------------------- /Chapter06/gpio-irq/gpio-irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* 17 | * Defines 18 | */ 19 | 20 | #define NAME KBUILD_BASENAME 21 | 22 | struct keys_s { 23 | char *name; 24 | int gpio; 25 | int irq; 26 | int btn; 27 | }; 28 | 29 | /* 30 | * Module's parameters 31 | */ 32 | 33 | static int debug; 34 | module_param(debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 35 | MODULE_PARM_DESC(int, "Set to 1 to enable debugging messages"); 36 | 37 | static int ngpios; 38 | static int gpios[2] = { -1 , -1 }; 39 | module_param_array(gpios, int, &ngpios, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 40 | MODULE_PARM_DESC(gpios, "Defines the GPIOs number to be used as a list of" 41 | " numbers separated by commas."); 42 | 43 | /* Logging stuff */ 44 | #define __message(level, fmt, args...) \ 45 | printk(level "%s: " fmt "\n" , NAME , ## args) 46 | 47 | #define DBG(code) \ 48 | do { \ 49 | if (unlikely(debug)) do { \ 50 | code \ 51 | } while (0); \ 52 | } while (0) 53 | 54 | #define info(fmt, args...) \ 55 | __message(KERN_INFO, fmt , ## args) 56 | 57 | #define err(fmt, args...) \ 58 | __message(KERN_ERR, fmt , ## args) 59 | 60 | #define dbg(fmt, args...) \ 61 | do { \ 62 | if (unlikely(debug)) \ 63 | __message(KERN_DEBUG, fmt , ## args); \ 64 | } while (0) 65 | 66 | /* 67 | * Global variables 68 | */ 69 | 70 | static struct input_dev *b_dev; 71 | 72 | static struct keys_s keys[2] = { 73 | [0] = { 74 | .name = "0", 75 | .btn = KEY_0, 76 | .gpio = -1, 77 | .irq = -1, 78 | }, 79 | 80 | [1] = { 81 | .name = "1", 82 | .btn = KEY_1, 83 | .gpio = -1, 84 | .irq = -1, 85 | }, 86 | }; 87 | 88 | /* 89 | * IRQ handler 90 | */ 91 | 92 | static irqreturn_t irq_handler(int i, void *ptr, struct pt_regs *regs) 93 | { 94 | struct keys_s *key = (struct keys_s *) ptr; 95 | int status; 96 | 97 | /* Get the gpio status */ 98 | status = !!gpio_get_value(key->gpio); 99 | dbg("IRQ on GPIO%d status=%d", key->gpio, status); 100 | 101 | /* Report the button event */ 102 | input_report_key(b_dev, key->btn, status); 103 | input_sync(b_dev); 104 | 105 | return IRQ_HANDLED; 106 | } 107 | 108 | /* 109 | * Usage function 110 | */ 111 | 112 | static void usage(void) 113 | { 114 | err("usage: insmod %s [ debug=1 ] gpios=gpio1#,gpio2#", NAME); 115 | } 116 | 117 | /* 118 | * Module stuff 119 | */ 120 | 121 | static int __init gpioirq_init(void) 122 | { 123 | int i; 124 | int ret; 125 | 126 | /* Check the supplied GPIOs numbers */ 127 | if (ngpios != 2) { 128 | usage(); 129 | ret = -EINVAL; 130 | goto exit; 131 | } 132 | 133 | /* Request the GPIOs and then setting them up as needed */ 134 | for (i = 0; i < 2; i++) { 135 | dbg("got GPIO%d", gpios[i]); 136 | 137 | /* Is the GPIO line free? */ 138 | ret = gpio_request(gpios[i], NAME); 139 | if (ret) { 140 | err("unable to request GPIO%d\n", gpios[i]); 141 | goto free_gpios; 142 | } 143 | keys[i].gpio = gpios[i]; 144 | 145 | /* If so then setting it as input */ 146 | gpio_direction_input(gpios[i]); 147 | 148 | /* Is GPIO in pin IRQ capable? */ 149 | ret = gpio_to_irq(gpios[i]); 150 | if (ret < 0) { 151 | err("GPIO%d is not IRQ capable\n", gpios[i]); 152 | ret = -EINVAL; 153 | goto free_gpios; 154 | } 155 | keys[i].irq = ret; 156 | 157 | /* Then request the IRQ */ 158 | ret = request_irq(keys[i].irq, (irq_handler_t) irq_handler, 159 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 160 | NAME, &keys[i]); 161 | if (ret < 0) { 162 | err("unable to request IRQ%d for GPIO%d\n", 163 | keys[i].irq, keys[i].gpio); 164 | ret = -EINVAL; 165 | goto free_gpios; 166 | } 167 | dbg("GPIO%d (key=\"%s\") mapped on IRQ %d", 168 | keys[i].gpio, keys[i].name, keys[i].irq); 169 | } 170 | 171 | /* Allocate the input device */ 172 | b_dev = input_allocate_device(); 173 | if (!b_dev) { 174 | err("cannot allocate memory"); 175 | ret = -ENOMEM; 176 | goto free_gpios; 177 | } 178 | b_dev->evbit[0] = BIT_MASK(EV_KEY); 179 | b_dev->name = NAME; 180 | b_dev->dev.parent = NULL; 181 | b_dev->id.bustype = BUS_HOST; 182 | b_dev->id.vendor = 0x0001; 183 | b_dev->id.product = 0x0001; 184 | b_dev->id.version = 0x0001; 185 | 186 | /* Define the keys mapping */ 187 | for (i = 0; i < 2; i++) 188 | set_bit(keys[i].btn, b_dev->keybit); 189 | 190 | /* Register the input device */ 191 | ret = input_register_device(b_dev); 192 | if (ret) { 193 | err("cannot register input device"); 194 | goto free_dev; 195 | } 196 | 197 | info("input GPIO IRQ module loaded"); 198 | 199 | return 0; 200 | 201 | free_dev: 202 | input_free_device(b_dev); 203 | 204 | free_gpios: 205 | for ( ; i >= 0; i--) { 206 | if (keys[i].irq >= 0) 207 | free_irq(keys[i].irq, &keys[i]); 208 | if (keys[i].gpio >= 0) 209 | gpio_free(keys[i].gpio); 210 | } 211 | 212 | exit: 213 | return ret; 214 | } 215 | 216 | static void __exit gpioirq_exit(void) 217 | { 218 | int i; 219 | 220 | input_unregister_device(b_dev); 221 | 222 | for (i = 0; i < 2; i++) { 223 | dbg("freeing IRQ %d for GPIO%d...", keys[i].irq, keys[i].gpio); 224 | free_irq(keys[i].irq, &keys[i]); 225 | gpio_free(keys[i].gpio); 226 | } 227 | 228 | info("input GPIO IRQ module released"); 229 | } 230 | 231 | module_init(gpioirq_init); 232 | module_exit(gpioirq_exit); 233 | 234 | MODULE_AUTHOR("Rodolfo Giometti "); 235 | MODULE_DESCRIPTION("input GPIO IRQ module"); 236 | MODULE_LICENSE("GPL"); 237 | MODULE_VERSION("0.0.1"); 238 | -------------------------------------------------------------------------------- /Chapter06/gpio-irq/gpio-irq.c.OK: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* 16 | * Defines 17 | */ 18 | 19 | #define NAME KBUILD_BASENAME 20 | 21 | /* 22 | * Module's parameters 23 | */ 24 | 25 | static int debug; 26 | module_param(debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 27 | MODULE_PARM_DESC(int, "Set to 1 to enable debugging messages"); 28 | 29 | static int ngpios; 30 | static int gpios[2] = { -1 , -1 }; 31 | module_param_array(gpios, int, &ngpios, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 32 | MODULE_PARM_DESC(gpios, "Defines the GPIOs number to be used as a list of" 33 | " numbers separated by commas."); 34 | 35 | /* Logging stuff */ 36 | #define __message(level, fmt, args...) \ 37 | printk(level "%s: " fmt "\n" , NAME , ## args) 38 | 39 | #define DBG(code) \ 40 | do { \ 41 | if (unlikely(debug)) do { \ 42 | code \ 43 | } while (0); \ 44 | } while (0) 45 | 46 | #define info(fmt, args...) \ 47 | __message(KERN_INFO, fmt , ## args) 48 | 49 | #define err(fmt, args...) \ 50 | __message(KERN_ERR, fmt , ## args) 51 | 52 | #define dbg(fmt, args...) \ 53 | do { \ 54 | if (unlikely(debug)) \ 55 | __message(KERN_DEBUG, fmt , ## args); \ 56 | } while (0) 57 | 58 | /* 59 | * Global variables 60 | */ 61 | 62 | static int irqs[2] = { -1 , -1 }; 63 | 64 | /* 65 | * IRQ handler 66 | */ 67 | 68 | static irqreturn_t irq_handler(int i, void *ptr, struct pt_regs *regs) 69 | { 70 | int *gpio = (int *) ptr; 71 | int status; 72 | 73 | BUG_ON(!gpio); 74 | 75 | /* Get the gpio status */ 76 | status = !!gpio_get_value(*gpio); 77 | 78 | info("IRQ on GPIO%d status=%d", *gpio, status); 79 | 80 | return IRQ_HANDLED; 81 | } 82 | 83 | /* 84 | * Usage function 85 | */ 86 | 87 | static void usage(void) 88 | { 89 | printk(KERN_ERR "usage: insmod %s [ debug=1 ] " 90 | " gpios=gpio1#,gpio2#\n", NAME); 91 | } 92 | 93 | /* 94 | * Module stuff 95 | */ 96 | 97 | static int __init gpioirq_init(void) 98 | { 99 | int i; 100 | int ret; 101 | 102 | /* Check the supplied GPIOs numbers */ 103 | if (ngpios != 2) { 104 | usage(); 105 | goto exit; 106 | } 107 | 108 | /* Now let's start by requesting the GPIOs and then setting them up 109 | * as needed 110 | */ 111 | for (i = 0; i < 2; i++) { 112 | dbg("got GPIO%d", gpios[i]); 113 | 114 | /* Is the GPIO line free? */ 115 | ret = gpio_request(gpios[i], NAME); 116 | if (ret) { 117 | err("unable to request GPIO%d\n", gpios[i]); 118 | goto undo; 119 | } 120 | 121 | /* If so then setting it as input */ 122 | gpio_direction_input(gpios[i]); 123 | 124 | /* Is GPIO in pin IRQ capable? */ 125 | irqs[i] = gpio_to_irq(gpios[i]); 126 | if (irqs[i] < 0) { 127 | err("GPIO%d is not IRQ capable\n", gpios[i]); 128 | goto undo; 129 | } 130 | 131 | /* Then request the IRQ */ 132 | ret = request_irq(irqs[i], (irq_handler_t) irq_handler, 133 | IRQF_TRIGGER_FALLING, NAME, &gpios[i]); 134 | if (ret < 0) { 135 | err("unable to request IRQ%d for GPIO%d\n", 136 | irqs[i], gpios[i]); 137 | goto undo; 138 | } 139 | dbg("GPIO%d mapped on IRQ %d", gpios[i], irqs[i]); 140 | } 141 | 142 | printk(KERN_INFO "GPIO IRQ module loaded\n"); 143 | 144 | return 0; 145 | 146 | undo: 147 | for ( ; i >= 0; i--) { 148 | if (irqs[i] >= 0) 149 | free_irq(irqs[i], &gpios[i]); 150 | if (gpios[i] >= 0) 151 | gpio_free(gpios[i]); 152 | } 153 | 154 | exit: 155 | return -EINVAL; 156 | } 157 | 158 | static void __exit gpioirq_exit(void) 159 | { 160 | int i; 161 | 162 | for (i = 0; i < 2; i++) { 163 | dbg("freeing IRQ %d for GPIO%d...", irqs[i], gpios[i]); 164 | free_irq(irqs[i], &gpios[i]); 165 | gpio_free(gpios[i]); 166 | } 167 | 168 | printk(KERN_INFO "GPIO IRQ module released\n"); 169 | } 170 | 171 | module_init(gpioirq_init); 172 | module_exit(gpioirq_exit); 173 | 174 | MODULE_AUTHOR("Rodolfo Giometti "); 175 | MODULE_DESCRIPTION("GPIO IRQ module"); 176 | MODULE_LICENSE("GPL"); 177 | MODULE_VERSION("0.0.1"); 178 | -------------------------------------------------------------------------------- /Chapter06/gpio-poll.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $stream) { 22 | # Read the GPIO status 23 | fseek($stream, 0, SEEK_SET); 24 | $status = intval(fgets($stream)); 25 | 26 | # Get the filename from "/sys/class/gpio/gpioXX/value" 27 | $meta_data = stream_get_meta_data($stream); 28 | $gpio = basename(dirname($meta_data["uri"])); 29 | 30 | printf("$gpio status=$status\n"); 31 | } 32 | } 33 | ?> 34 | -------------------------------------------------------------------------------- /Chapter06/gpio-poll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import select 7 | 8 | gpio24 = "/sys/class/gpio/gpio24/value" 9 | gpio91 = "/sys/class/gpio/gpio91/value" 10 | 11 | # Get the GPIOs streams 12 | stream24 = open(gpio24, 'r'); 13 | stream91 = open(gpio91, 'r'); 14 | 15 | while True : 16 | # Set up stream sets for the select() 17 | read = [] 18 | write = [] 19 | exept = [stream24, stream91] 20 | 21 | # Wait for IRQs (without timeout)... 22 | r, w, e = select.select(read, write, exept) 23 | for i, input in enumerate(e) : 24 | # Read the GPIO status 25 | input.seek(0, 0) 26 | status = input.read().rstrip("\n") 27 | 28 | # Get the filename from "/sys/class/gpio/gpioXX/value" 29 | path = os.path.dirname(input.name) 30 | gpio = os.path.basename(path) 31 | 32 | print("%s status=%s" % (gpio, status)) 33 | -------------------------------------------------------------------------------- /Chapter06/gpio-poll/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = gpio-poll 2 | CFLAGS = -Wall -O2 -D_GNU_SOURCE 3 | 4 | MACHINE = $(shell awk '/Hardware/ { print $$3 }' < /proc/cpuinfo) 5 | ifeq ($(MACHINE),Atmel) 6 | CFLAGS += -D_ATMEL_GPIOS 7 | endif 8 | 9 | all: $(TARGET) 10 | 11 | clean: 12 | rm -rf $(TARGET) 13 | -------------------------------------------------------------------------------- /Chapter06/gpio-poll/gpio-poll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter06/gpio-poll/gpio-poll -------------------------------------------------------------------------------- /Chapter06/gpio-poll/gpio-poll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Defines 13 | */ 14 | 15 | #define NAME program_invocation_short_name 16 | #define SYSFS_GPIO_DIR "/sys/class/gpio" 17 | #define POLL_TIMEOUT (1 * 1000) /* in ms */ 18 | 19 | /* Some useful GPIO defines */ 20 | #define GPIO_IN 0 21 | #define GPIO_OUT 1 22 | #define GPIO_NONE "none" 23 | #define GPIO_RISING "rising" 24 | #define GPIO_FALLING "falling" 25 | #define GPIO_BOTH "both" 26 | 27 | /* Logging & other stuff */ 28 | 29 | #define __message(stream, fmt, args...) \ 30 | fprintf(stream, "%s: " fmt "\n" , NAME , ## args) 31 | 32 | #define DBG(code) \ 33 | do { \ 34 | if (unlikely(enable_debug)) do { \ 35 | code \ 36 | } while (0); \ 37 | } while (0) 38 | 39 | #define info(fmt, args...) \ 40 | __message(stdout, fmt , ## args) 41 | 42 | #define err(fmt, args...) \ 43 | __message(stderr, fmt , ## args) 44 | 45 | #define dbg(fmt, args...) \ 46 | do { \ 47 | if (unlikely(enable_debug)) \ 48 | __message(stderr, fmt , ## args); \ 49 | } while (0) 50 | 51 | #define BUILD_BUG_ON_ZERO(e) \ 52 | (sizeof(char[1 - 2 * !!(e)]) - 1) 53 | #define __must_be_array(a) \ 54 | BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), \ 55 | typeof(&a[0]))) 56 | #define ARRAY_SIZE(arr) \ 57 | (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) 58 | 59 | #define unlikely(x) __builtin_expect(!!(x), 0) 60 | #define BUG() \ 61 | do { \ 62 | err("fatal error in %s():%d", __func__, __LINE__); \ 63 | exit(EXIT_FAILURE); \ 64 | } while (0) 65 | #define EXIT_ON(condition) \ 66 | do { \ 67 | if (unlikely(condition)) \ 68 | BUG(); \ 69 | } while(0) 70 | #define BUG_ON(condition) EXIT_ON(condition) 71 | 72 | #define WARN() \ 73 | do { \ 74 | err("warning notice in %s():%d", __func__, __LINE__); \ 75 | } while (0) 76 | #define WARN_ON(condition) \ 77 | do { \ 78 | if (unlikely(condition)) \ 79 | WARN(); \ 80 | } while(0) 81 | 82 | /* 83 | * GPIO number to GPIO name conversion function 84 | * 85 | * This is needed in order to keep in count the Atmel's non-standard names. 86 | * The code can be easily extended in order to suite all needs just adding 87 | * a new ordered entry in the lut[] array. 88 | */ 89 | 90 | #ifdef _ATMEL_GPIOS 91 | 92 | char *lut[] = { 93 | [57] = "pioB25", 94 | [58] = "pioB26", 95 | [59] = "pioB27", 96 | }; 97 | 98 | #else /* ! _ATMEL_GPIOS */ 99 | 100 | char *lut[] = { 101 | [24] = "gpio24", 102 | [91] = "gpio91", 103 | [191] = "gpio191", 104 | [200] = "gpio200", 105 | }; 106 | 107 | #endif /* _ATMEL_GPIOS */ 108 | 109 | char *gpio2name(int gpio) 110 | { 111 | BUG_ON(gpio < 0); 112 | 113 | /* Check for gpio index out of range or if the corresponding entry 114 | * into the lut[] array is not defined 115 | */ 116 | if (gpio >= ARRAY_SIZE(lut) || lut[gpio] == NULL) { 117 | err("unable to get GPIO%d name! " 118 | "Consider to fix up the lut[] array", gpio); 119 | BUG(); 120 | } 121 | 122 | return lut[gpio]; 123 | } 124 | 125 | /* 126 | * Global variables 127 | */ 128 | 129 | int enable_debug; 130 | int gpio[2]; 131 | 132 | /* 133 | * GPIOs management functions 134 | */ 135 | 136 | int gpio_export(unsigned int gpio) 137 | { 138 | int fd, len; 139 | char *buf; 140 | 141 | fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY); 142 | if (fd < 0) 143 | return fd; 144 | 145 | len = asprintf(&buf, "%d", gpio); 146 | BUG_ON(len < 0); 147 | 148 | write(fd, buf, len); 149 | close(fd); 150 | 151 | free(buf); 152 | return 0; 153 | } 154 | 155 | int gpio_unexport(unsigned int gpio) 156 | { 157 | int fd, len; 158 | char *buf; 159 | 160 | fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY); 161 | if (fd < 0) 162 | return fd; 163 | 164 | len = asprintf(&buf, "%d", gpio); 165 | BUG_ON(len < 0); 166 | 167 | write(fd, buf, len); 168 | close(fd); 169 | 170 | free(buf); 171 | return 0; 172 | } 173 | 174 | int gpio_set_dir(unsigned int gpio, unsigned int out_flag) 175 | { 176 | int fd, len; 177 | char *buf; 178 | 179 | len = asprintf(&buf, SYSFS_GPIO_DIR "/%s/direction", gpio2name(gpio)); 180 | BUG_ON(len < 0); 181 | 182 | fd = open(buf, O_WRONLY); 183 | if (fd < 0) { 184 | free(buf); 185 | return fd; 186 | } 187 | 188 | if (out_flag) 189 | write(fd, "out", 4); 190 | else 191 | write(fd, "in", 3); 192 | 193 | free(buf); 194 | close(fd); 195 | 196 | return 0; 197 | } 198 | 199 | int gpio_set_value(unsigned int gpio, unsigned int value) 200 | { 201 | int fd, len; 202 | char *buf; 203 | 204 | len = asprintf(&buf, SYSFS_GPIO_DIR "/%s/value", gpio2name(gpio)); 205 | BUG_ON(len < 0); 206 | 207 | fd = open(buf, O_WRONLY); 208 | if (fd < 0) { 209 | free(buf); 210 | return fd; 211 | } 212 | 213 | if (value) 214 | write(fd, "1", 2); 215 | else 216 | write(fd, "0", 2); 217 | 218 | free(buf); 219 | close(fd); 220 | 221 | return 0; 222 | } 223 | 224 | int gpio_get_value(unsigned int gpio, unsigned int *value) 225 | { 226 | int fd, len, n; 227 | char *buf; 228 | char ch; 229 | 230 | len = asprintf(&buf, SYSFS_GPIO_DIR "/%s/value", gpio2name(gpio)); 231 | BUG_ON(len < 0); 232 | 233 | fd = open(buf, O_RDONLY); 234 | if (fd < 0) 235 | return fd; 236 | 237 | n = read(fd, &ch, 1); 238 | 239 | *value = ch != '0' ? 1 : 0; 240 | 241 | free(buf); 242 | close(fd); 243 | 244 | return n; 245 | } 246 | 247 | 248 | int gpio_set_edge(unsigned int gpio, char *edge) 249 | { 250 | int fd, len, n; 251 | char *buf; 252 | 253 | len = asprintf(&buf, SYSFS_GPIO_DIR "/%s/edge", gpio2name(gpio)); 254 | BUG_ON(len < 0); 255 | 256 | fd = open(buf, O_WRONLY); 257 | if (fd < 0) 258 | return fd; 259 | 260 | n = write(fd, edge, strlen(edge) + 1); 261 | 262 | free(buf); 263 | close(fd); 264 | 265 | return n; 266 | } 267 | 268 | int gpio_fd_open(unsigned int gpio) 269 | { 270 | int fd, len; 271 | char *buf; 272 | 273 | len = asprintf(&buf, SYSFS_GPIO_DIR "/%s/value", gpio2name(gpio)); 274 | BUG_ON(len < 0); 275 | 276 | fd = open(buf, O_RDONLY | O_NONBLOCK ); 277 | 278 | free(buf); 279 | 280 | return fd; 281 | } 282 | 283 | int gpio_fd_close(int fd) 284 | { 285 | return close(fd); 286 | } 287 | 288 | /* 289 | * Clean up function 290 | */ 291 | 292 | static void cleanup(void) 293 | { 294 | int i; 295 | 296 | dbg("clean up"); 297 | 298 | for (i = 0; i < 2; i++) 299 | gpio_unexport(gpio[i]); 300 | } 301 | 302 | static void sighand_exit(int signo) 303 | { 304 | dbg("sighand_exit"); 305 | 306 | /* Call atexit() hooks */ 307 | exit(EXIT_SUCCESS); 308 | } 309 | 310 | /* 311 | * Usage 312 | */ 313 | 314 | void usage(void) 315 | { 316 | int i; 317 | 318 | fprintf(stderr, "usage: %s [--help|-h] [--debug|-d] gpio1# gpio2#\n", 319 | NAME); 320 | fprintf(stderr, "\n\tSupported GPIOs are:\n"); 321 | for (i = 0; i < ARRAY_SIZE(lut); i++) 322 | if (lut[i]) 323 | fprintf(stderr, "\t\tGPIO%d named as %s\n", 324 | i, gpio2name(i)); 325 | 326 | exit(EXIT_FAILURE); 327 | } 328 | 329 | /* 330 | * Main 331 | */ 332 | 333 | int main(int argc, char *argv[]) 334 | { 335 | int c; 336 | struct option long_options[] = { 337 | {"help", no_argument, 0, 'h'}, 338 | {"debug", no_argument, 0, 'd'}, 339 | }; 340 | sighandler_t sig_h; 341 | struct pollfd fdset[2]; 342 | int i; 343 | int gpio_fd[2]; 344 | unsigned int val; 345 | char v; 346 | int ret; 347 | 348 | /* Register signal handlers in order to do some clean up stuff 349 | * at exit time... 350 | */ 351 | atexit(cleanup); 352 | sig_h = signal(SIGTERM, sighand_exit); /* clean up on SIGTERM */ 353 | if (sig_h == SIG_ERR) { 354 | err("unable to catch SIGTERM"); 355 | exit(EXIT_FAILURE); 356 | } 357 | sig_h = signal(SIGINT, sighand_exit); 358 | if (sig_h == SIG_ERR) { 359 | err("unable to catch SIGINT"); 360 | exit(EXIT_FAILURE); 361 | } 362 | 363 | /* Check the command line */ 364 | while (1) { 365 | /* `getopt_long' stores the option index here. */ 366 | int option_index = 0; 367 | 368 | c = getopt_long(argc, argv, "hd", 369 | long_options, &option_index); 370 | 371 | /* Detect the end of the options. */ 372 | if (c == -1) 373 | break; 374 | 375 | switch (c) { 376 | case 0: 377 | /* If this option set a flag, do nothing else now */ 378 | BUG_ON(long_options[option_index].flag == NULL); 379 | 380 | break; 381 | 382 | case 'h': /* --help */ 383 | usage(); 384 | 385 | case 'd': /* --debug */ 386 | enable_debug++; 387 | 388 | break; 389 | 390 | case ':': 391 | /* "getopt_long" already printed an error message */ 392 | exit(EXIT_FAILURE); 393 | 394 | case '?': 395 | /* "getopt_long" already printed an error message */ 396 | err("unrecognized option \"%s\"", argv[optind - 1]); 397 | exit(EXIT_FAILURE); 398 | 399 | default: 400 | BUG(); 401 | } 402 | } 403 | dbg("debug is on (level=%d)", enable_debug); 404 | 405 | /* 406 | * Parse any remaining command line arguments (not options) 407 | */ 408 | 409 | argc -= optind; 410 | argv += optind; 411 | if (argc < 2) 412 | usage(); 413 | 414 | for (i = 0; i < 2; i++) { 415 | ret = sscanf(argv[i], "%d", &gpio[i]); 416 | if (ret != 1) { 417 | err("invalid entry \"%s\"", argv[i]); 418 | exit(EXIT_FAILURE); 419 | } 420 | info("got GPIO%d named as %s", gpio[i], gpio2name(gpio[i])); 421 | } 422 | 423 | /* 424 | * Now we have to set up both GPIOs as input falling edge 425 | */ 426 | 427 | for (i = 0; i < 2; i++) { 428 | ret = gpio_export(gpio[i]); 429 | if (ret < 0) { 430 | err("unable to export GPIO%d", gpio[i]); 431 | exit(EXIT_FAILURE); 432 | } 433 | 434 | ret = gpio_set_dir(gpio[i], GPIO_IN); 435 | if (ret < 0) { 436 | err("unable to set direction for GPIO%d", gpio[i]); 437 | exit(EXIT_FAILURE); 438 | } 439 | 440 | ret = gpio_set_edge(gpio[i], GPIO_FALLING); 441 | if (ret < 0) { 442 | err("unable to set edge for GPIO%d", gpio[i]); 443 | exit(EXIT_FAILURE); 444 | } 445 | 446 | ret = gpio_fd_open(gpio[i]); 447 | if (ret < 0) { 448 | err("unable to open GPIO%d", gpio[i]); 449 | exit(EXIT_FAILURE); 450 | } 451 | gpio_fd[i] = ret; 452 | } 453 | 454 | /* 455 | * Do the job 456 | */ 457 | 458 | while (1) { 459 | /* Set up the fdset data structs */ 460 | memset((void*) fdset, 0, sizeof(fdset)); 461 | for (i = 0; i < 2; i++) { 462 | fdset[i].fd = gpio_fd[i]; 463 | fdset[i].events = POLLPRI; 464 | } 465 | 466 | /* Do the poll() with timeout */ 467 | ret = poll(fdset, 2, POLL_TIMEOUT); 468 | BUG_ON(ret < 0); 469 | if (ret == 0) { 470 | /* No IRQs received! 471 | * If debug is enabled then print GPIOs statuses, 472 | * otherwise just print a dot "." 473 | */ 474 | if (enable_debug) { 475 | for (i = 0; i < 2; i++) { 476 | ret = gpio_get_value(gpio[i], &val); 477 | BUG_ON(ret < 0); 478 | dbg("read() GPIO%d=%d", gpio[i], val); 479 | } 480 | } else { 481 | printf("."); 482 | fflush(stdout); 483 | } 484 | } else { 485 | /* IRQ received! 486 | * Print out the new GPIO status 487 | */ 488 | for (i = 0; i < 2; i++) { 489 | if (fdset[i].revents & POLLPRI) { 490 | ret = lseek(fdset[i].fd, SEEK_SET, 0); 491 | BUG_ON(ret < 0); 492 | ret = read(fdset[i].fd, &v, 1); 493 | BUG_ON(ret < 1); 494 | 495 | if (ret == 1) { 496 | info("poll() GPIO%d=%c", 497 | gpio[i], v); 498 | } 499 | } 500 | } 501 | } 502 | } 503 | 504 | /* Never reached */ 505 | 506 | return 0; 507 | } 508 | -------------------------------------------------------------------------------- /Chapter07/README.md: -------------------------------------------------------------------------------- 1 | Chapter 7 - Serial Ports and TTY Devices - TTY 2 | ============================================== 3 | 4 | Here the code from chapter 7 - "Serial Ports and TTY Devices - TTY" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some examples about how to get access to a serial port by using 9 | C or scripting languages. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter07/rfid_lf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import getopt 7 | import string 8 | import serial 9 | 10 | NAME = os.path.basename(sys.argv[0]) 11 | 12 | # 13 | # Local functions 14 | # 15 | 16 | def error(*objs): 17 | print(NAME, ": ", *objs, file = sys.stderr) 18 | 19 | 20 | def reader(ser): 21 | while True: 22 | line = ser.readline() 23 | line = filter(lambda x: x in string.printable, line) 24 | print(line.replace("\n", "")), 25 | 26 | def usage(): 27 | print("usage: ", NAME, " [-h] ", file = sys.stderr) 28 | sys.exit(2); 29 | 30 | # 31 | # Main 32 | # 33 | 34 | try: 35 | opts, args = getopt.getopt(sys.argv[1:], "h", 36 | ["help"]) 37 | except getopt.GetoptError, err: 38 | # Print help information and exit: 39 | error(str(err)) 40 | usage() 41 | 42 | for o, a in opts: 43 | if o in ("-h", "--help"): 44 | usage() 45 | else: 46 | assert False, "unhandled option" 47 | 48 | # Check command line 49 | if len(args) < 1: 50 | usage() 51 | dev = args[0] 52 | 53 | # Configure the serial connections 54 | ser = serial.Serial( 55 | port = dev, 56 | baudrate = 9600, 57 | bytesize = 8, 58 | parity = 'N', 59 | stopbits = 1, 60 | timeout = None, 61 | xonxoff = 0, 62 | rtscts = 0 63 | ) 64 | 65 | reader(ser) 66 | 67 | ser.close() 68 | -------------------------------------------------------------------------------- /Chapter07/scat/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = scat 2 | CFLAGS = -Wall -O2 -D_GNU_SOURCE 3 | 4 | all: $(TARGET) 5 | 6 | clean: 7 | rm -rf $(TARGET) 8 | -------------------------------------------------------------------------------- /Chapter07/scat/scat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NAME program_invocation_short_name 14 | #define VERSION "0.10.0" 15 | 16 | /* 17 | * Defines 18 | */ 19 | 20 | #define DEVICE "/dev/ttyS0" 21 | #define BAUDRATE 9600 22 | #ifndef PAGE_SIZE 23 | #define PAGE_SIZE 4096 24 | #endif 25 | 26 | /* Logging & other stuff */ 27 | 28 | #define __message(stream, fmt, args...) \ 29 | fprintf(stream, "%s: " fmt "\n" , NAME , ## args) 30 | 31 | #define DBG(code) \ 32 | do { \ 33 | if (unlikely(enable_debug)) do { \ 34 | code \ 35 | } while (0); \ 36 | } while (0) 37 | 38 | #define info(fmt, args...) \ 39 | __message(stdout, fmt , ## args) 40 | 41 | #define err(fmt, args...) \ 42 | __message(stderr, fmt , ## args) 43 | 44 | #define dbg(fmt, args...) \ 45 | do { \ 46 | if (unlikely(enable_debug)) \ 47 | __message(stderr, fmt , ## args); \ 48 | } while (0) 49 | 50 | #define BUILD_BUG_ON_ZERO(e) \ 51 | (sizeof(char[1 - 2 * !!(e)]) - 1) 52 | #define __must_be_array(a) \ 53 | BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), \ 54 | typeof(&a[0]))) 55 | #define ARRAY_SIZE(arr) \ 56 | (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) 57 | 58 | #define unlikely(x) __builtin_expect(!!(x), 0) 59 | #define BUG() \ 60 | do { \ 61 | err("fatal error in %s():%d", __func__, __LINE__); \ 62 | exit(EXIT_FAILURE); \ 63 | } while (0) 64 | #define EXIT_ON(condition) \ 65 | do { \ 66 | if (unlikely(condition)) \ 67 | BUG(); \ 68 | } while(0) 69 | #define BUG_ON(condition) EXIT_ON(condition) 70 | 71 | #define WARN() \ 72 | do { \ 73 | err("warning notice in %s():%d", __func__, __LINE__); \ 74 | } while (0) 75 | #define WARN_ON(condition) \ 76 | do { \ 77 | if (unlikely(condition)) \ 78 | WARN(); \ 79 | } while(0) 80 | 81 | /* 82 | * Serial port management 83 | */ 84 | 85 | void flush_serial(int fd) 86 | { 87 | tcflush(fd, TCIOFLUSH); 88 | } 89 | 90 | int set_serial(int fd, int rate) 91 | { 92 | struct termios term; 93 | 94 | int ret; 95 | 96 | /* Sanity checks */ 97 | switch (rate) { 98 | case 9600 : 99 | rate = B9600; 100 | break; 101 | 102 | case 19200 : 103 | rate = B19200; 104 | break; 105 | 106 | case 38400 : 107 | rate = B38400; 108 | break; 109 | 110 | case 57600 : 111 | rate = B57600; 112 | break; 113 | 114 | case 115200 : 115 | rate = B115200; 116 | break; 117 | 118 | default : /* error */ 119 | return -1; 120 | } 121 | 122 | ret = tcgetattr(fd, &term); 123 | if (ret < 0) 124 | return ret; 125 | 126 | ret = cfsetispeed(&term, rate); 127 | if (ret < 0) 128 | return ret; 129 | ret = cfsetospeed(&term, rate); 130 | if (ret < 0) 131 | return ret; 132 | 133 | cfmakeraw(&term); 134 | term.c_cc[VTIME] = 0; 135 | term.c_cc[VMIN] = 1; 136 | ret = tcsetattr(fd, TCSANOW, &term); 137 | 138 | return 0; 139 | } 140 | 141 | int open_serial(const char *name) 142 | { 143 | char *dev; 144 | 145 | if (!name) { 146 | dev = getenv("SERIAL_DEVICE"); 147 | if (dev) 148 | name = dev; 149 | else 150 | name = DEVICE; 151 | } 152 | 153 | return open(name, O_RDWR | O_NOCTTY); 154 | } 155 | 156 | void close_serial(int fd) 157 | { 158 | close(fd); 159 | } 160 | 161 | /* 162 | * Global variables 163 | */ 164 | 165 | int enable_debug; 166 | 167 | /* 168 | * Usage 169 | */ 170 | 171 | void usage(void) 172 | { 173 | fprintf(stderr, "usage: %s \n", NAME); 174 | fprintf(stderr, " where are:\n"); 175 | fprintf(stderr, " [-h | --help] : show this help\n"); 176 | fprintf(stderr, " [-d | --debug] : enable debug\n"); 177 | fprintf(stderr, " [-b | --baud ] : set baudrate (default %d)\n", BAUDRATE); 178 | fprintf(stderr, " [-D | --device ] : use device (default %s)\n", DEVICE); 179 | 180 | exit(EXIT_FAILURE); 181 | } 182 | 183 | /* 184 | * Main 185 | */ 186 | 187 | int main(int argc, char *argv[]) 188 | { 189 | int c; 190 | static struct option long_options[] = { 191 | {"help", no_argument, 0, 'h'}, 192 | {"debug", no_argument, 0, 'd'}, 193 | {"baud", required_argument, 0, 'b'}, 194 | {"device", required_argument, 0, 'D'}, 195 | {0, 0, 0, 0} 196 | }; 197 | 198 | char *device = DEVICE; 199 | int baudrate = BAUDRATE; 200 | char buf[PAGE_SIZE]; 201 | int fd; 202 | int i, n; 203 | int ret; 204 | 205 | /* Check the command line */ 206 | while (1) { 207 | /* `getopt_long' stores the option index here. */ 208 | int option_index = 0; 209 | 210 | c = getopt_long(argc, argv, "hdb:D:", 211 | long_options, &option_index); 212 | 213 | /* Detect the end of the options. */ 214 | if (c == -1) 215 | break; 216 | 217 | switch (c) { 218 | case 0: 219 | /* If this option set a flag, do nothing else now */ 220 | BUG_ON(long_options[option_index].flag == NULL); 221 | 222 | break; 223 | 224 | case 'h' : /* --help */ 225 | usage(); 226 | 227 | case 'd': /* --debug */ 228 | enable_debug++; 229 | 230 | break; 231 | 232 | case 'b' : /* --baud */ 233 | if (sscanf(optarg, "%d", &baudrate) < 1) { 234 | err("must specify a baud rate value"); 235 | exit(EXIT_FAILURE); 236 | } 237 | 238 | break; 239 | 240 | case 'D' : /* --device */ 241 | device = optarg; 242 | break; 243 | 244 | case ':' : 245 | /* "getopt_long" already printed an error message */ 246 | exit(EXIT_FAILURE); 247 | 248 | case '?' : 249 | /* "getopt_long" already printed an error message */ 250 | err("unrecognized option \"%s\"", argv[optind - 1]); 251 | exit(EXIT_FAILURE); 252 | 253 | default : 254 | BUG(); 255 | } 256 | } 257 | dbg("debug is on (level=%d)", enable_debug); 258 | 259 | /* 260 | * Parse any remaining command line arguments (not options) 261 | */ 262 | 263 | argc -= optind; 264 | argv += optind; 265 | 266 | /* Open the serial device */ 267 | ret = open_serial(device); 268 | if (ret < 0) { 269 | err("unable to open the serial device"); 270 | exit(EXIT_FAILURE); 271 | } 272 | fd = ret; 273 | 274 | /* Set up the serial device by setting the user defined baudrate and 275 | * the raw mode 276 | */ 277 | ret = set_serial(fd, baudrate); 278 | if (ret < 0) { 279 | err("unable to setup the serial device"); 280 | exit(EXIT_FAILURE); 281 | } 282 | 283 | /* 284 | * Do the job 285 | */ 286 | 287 | while (1) { 288 | /* Read the data from the serial port */ 289 | ret = read(fd, buf, ARRAY_SIZE(buf)); 290 | if (ret < 0) { 291 | err("error reading from the serial port"); 292 | exit(EXIT_FAILURE); 293 | } 294 | n = ret; 295 | 296 | /* Check for End-Of-File condition */ 297 | if (n == 0) 298 | break; 299 | 300 | /* Write the just read data to the stdout replacing the 301 | * non printable characters with a "." 302 | */ 303 | for (i = 0; i < n; i++) { 304 | if (buf[i] == '\n' || buf[i] == '\r' || 305 | isprint((int) buf[i])) 306 | ret = printf("%c", buf[i]); 307 | else 308 | ret = printf("."); 309 | if (ret < 0) { 310 | err("error reading from the serial port"); 311 | exit(EXIT_FAILURE); 312 | } 313 | } 314 | 315 | /* Flush out the data */ 316 | fflush(stdout); 317 | } 318 | 319 | close_serial(fd); 320 | 321 | return 0; 322 | } 323 | -------------------------------------------------------------------------------- /Chapter08/README.md: -------------------------------------------------------------------------------- 1 | Chapter 8 - Universal Serial Bus - USB 2 | ====================================== 3 | 4 | Here the code from chapter 8 - "Universal Serial Bus - USB" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some example of USB devices management in both host and gadget mode. 9 | 10 | See the URL 11 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 12 | for further info. 13 | -------------------------------------------------------------------------------- /Chapter08/key_read.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import getopt 7 | import string 8 | from evdev import InputDevice, ecodes 9 | from select import select 10 | 11 | NAME = os.path.basename(sys.argv[0]) 12 | 13 | keys = ".^1234567890....qwertzuiop....asdfghjkl.....yxcvbnm......................." 14 | 15 | # 16 | # Local functions 17 | # 18 | 19 | def error(*objs): 20 | print(NAME, ": ", *objs, file = sys.stderr) 21 | 22 | def usage(): 23 | print("usage: ", NAME, " [-h] ", file = sys.stderr) 24 | sys.exit(2); 25 | 26 | # 27 | # Main 28 | # 29 | 30 | try: 31 | opts, args = getopt.getopt(sys.argv[1:], "h", 32 | ["help"]) 33 | except getopt.GetoptError, err: 34 | # Print help information and exit: 35 | error(str(err)) 36 | usage() 37 | 38 | for o, a in opts: 39 | if o in ("-h", "--help"): 40 | usage() 41 | else: 42 | assert False, "unhandled option" 43 | 44 | # Check command line 45 | if len(args) < 1: 46 | usage() 47 | 48 | # Try to open the input device 49 | try: 50 | dev = InputDevice(args[0]) 51 | except: 52 | error("invalid input device", args[0]) 53 | sys.exit(1); 54 | 55 | # Now read data from the input device printing only letters and numbers 56 | while True: 57 | r, w, x = select([dev], [], []) 58 | for event in dev.read(): 59 | # Print key pressed events only 60 | if event.type == ecodes.EV_KEY and event.value == 1: 61 | print(keys[event.code], end = "") 62 | sys.stdout.flush() # needed by print() 63 | -------------------------------------------------------------------------------- /Chapter08/usb_sendrecv/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = usb_sendrecv 2 | 3 | CFLAGS := -Wall -O2 -D_GNU_SOURCE $(shell pkg-config libusb-1.0 --cflags) 4 | LDLIBS := $(shell pkg-config libusb-1.0 --libs) 5 | 6 | all: $(TARGET) 7 | 8 | clean: 9 | rm -rf $(TARGET) 10 | 11 | phony: all clean 12 | -------------------------------------------------------------------------------- /Chapter08/usb_sendrecv/usb_sendrecv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * Defines 11 | */ 12 | 13 | #define NAME program_invocation_short_name 14 | 15 | /* The g_zero default USB vendor:device product numbers */ 16 | #define VENDOR_ID 0x1a0a 17 | #define PRODUCT_ID 0xbadd 18 | 19 | /* Logging & other stuff */ 20 | 21 | #define __message(stream, fmt, args...) \ 22 | fprintf(stream, "%s: " fmt "\n" , NAME , ## args) 23 | 24 | #define DBG(code) \ 25 | do { \ 26 | if (unlikely(enable_debug)) do { \ 27 | code \ 28 | } while (0); \ 29 | } while (0) 30 | 31 | #define info(fmt, args...) \ 32 | __message(stdout, fmt , ## args) 33 | 34 | #define err(fmt, args...) \ 35 | __message(stderr, fmt , ## args) 36 | 37 | #define dbg(fmt, args...) \ 38 | do { \ 39 | if (unlikely(enable_debug)) \ 40 | __message(stderr, fmt , ## args); \ 41 | } while (0) 42 | 43 | #define BUILD_BUG_ON_ZERO(e) \ 44 | (sizeof(char[1 - 2 * !!(e)]) - 1) 45 | #define __must_be_array(a) \ 46 | BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), \ 47 | typeof(&a[0]))) 48 | #define ARRAY_SIZE(arr) \ 49 | (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) 50 | 51 | #define unlikely(x) __builtin_expect(!!(x), 0) 52 | #define BUG() \ 53 | do { \ 54 | err("fatal error in %s():%d", __func__, __LINE__); \ 55 | exit(EXIT_FAILURE); \ 56 | } while (0) 57 | #define EXIT_ON(condition) \ 58 | do { \ 59 | if (unlikely(condition)) \ 60 | BUG(); \ 61 | } while(0) 62 | #define BUG_ON(condition) EXIT_ON(condition) 63 | 64 | #define WARN() \ 65 | do { \ 66 | err("warning notice in %s():%d", __func__, __LINE__); \ 67 | } while (0) 68 | #define WARN_ON(condition) \ 69 | do { \ 70 | if (unlikely(condition)) \ 71 | WARN(); \ 72 | } while(0) 73 | 74 | /* 75 | * Global variables 76 | */ 77 | 78 | uint8_t buffer[4096] = "TEST STRING\n"; 79 | 80 | /* 81 | * Main 82 | */ 83 | 84 | int main(int argc, char *argv[]) 85 | { 86 | libusb_device_handle *handle; 87 | int flag = 0; /* set to 1 if kernel driver detached */ 88 | int n; 89 | int ret; 90 | 91 | /* Init th libusb */ 92 | ret = libusb_init(NULL); 93 | if (ret < 0) { 94 | err("unable to init libusb"); 95 | exit(-1); 96 | } 97 | 98 | /* Check for g_zero device is connected to the system */ 99 | handle = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID); 100 | if (!handle) { 101 | err("unable to open g_zero device"); 102 | exit(-1); 103 | } 104 | info("g_zero device found"); 105 | 106 | /* 107 | * Check whether a kernel driver is attached to interface #0. 108 | * If so, we'll need to detach it. 109 | */ 110 | if (libusb_kernel_driver_active(handle, 0)) { 111 | ret = libusb_detach_kernel_driver(handle, 0); 112 | if (ret == 0) { 113 | flag = 1; 114 | } else { 115 | err("error detaching kernel driver"); 116 | exit(-1); 117 | } 118 | } 119 | 120 | /* Claim interface #0 */ 121 | ret = libusb_claim_interface(handle, 0); 122 | if (ret) { 123 | err("error claiming interface"); 124 | exit(-1); 125 | } 126 | 127 | /* Send an all-zeros message to endpoint 0x01 */ 128 | ret = libusb_bulk_transfer(handle, 0x01, buffer, 129 | sizeof(buffer), &n, 100); 130 | if (ret) { 131 | err("error sending message to device ret=%d", ret); 132 | exit(-1); 133 | } 134 | info("%d bytes transmitted successfully", n); 135 | 136 | sleep(1); 137 | 138 | /* Receive an all-zeros message from endpoint 0x81 */ 139 | ret = libusb_bulk_transfer(handle, 0x81, buffer, 140 | sizeof(buffer), &n, 100); 141 | if (ret) { 142 | err("error receiving message from device ret=%d", ret); 143 | exit(-1); 144 | } 145 | if (n != sizeof(buffer)) { 146 | err("error receiving %d bytes while expecting %ld", 147 | n, sizeof(buffer)); 148 | exit(-1); 149 | } 150 | info("%d bytes received successfully", n); 151 | 152 | printf("string=%s\n", buffer); 153 | 154 | /* Release interface #0 */ 155 | ret = libusb_release_interface(handle, 0); 156 | if (ret) { 157 | err("error releasing interface"); 158 | exit(-1); 159 | } 160 | 161 | /* 162 | * If we detached a kernel driver from interface #0 earlier, we'll now 163 | * need to attach it again. 164 | */ 165 | if (flag) 166 | libusb_attach_kernel_driver(handle, 0); 167 | 168 | libusb_exit(NULL); 169 | 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /Chapter09/A5D3-IIO-HTU21D+T5403-dts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..0c9b183 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -68,6 +68,17 @@ 6 | i2c0: i2c@f0014000 { 7 | pinctrl-0 = <&pinctrl_i2c0_pu>; 8 | status = "okay"; 9 | + clock-frequency = <100000>; 10 | + 11 | + htu21: htu21@40 { 12 | + compatible = "htu21"; 13 | + reg = <0x40>; 14 | + }; 15 | + 16 | + t5403: t5403@77 { 17 | + compatible = "t5403"; 18 | + reg = <0x77>; 19 | + }; 20 | }; 21 | 22 | i2c1: i2c@f0018000 { 23 | -------------------------------------------------------------------------------- /Chapter09/A5D3-TTY-SC16IS7-dts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..d90e7b3 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -29,6 +29,12 @@ 6 | main_xtal { 7 | clock-frequency = <12000000>; 8 | }; 9 | + 10 | + sc16is7xx_ck: sc16is7xx_ck { 11 | + compatible = "fixed-clock"; 12 | + #clock-cells = <0>; 13 | + clock-frequency = <14745600>; 14 | + }; 15 | }; 16 | 17 | ahb { 18 | @@ -68,6 +74,14 @@ 19 | i2c0: i2c@f0014000 { 20 | pinctrl-0 = <&pinctrl_i2c0_pu>; 21 | status = "okay"; 22 | + 23 | + sc16is750: sc16is750@4d { 24 | + compatible = "nxp,sc16is750"; 25 | + reg = <0x4d>; 26 | + 27 | + clocks = <&sc16is7xx_ck>; 28 | + interrupts-extended = <&pioA 22 IRQ_TYPE_EDGE_FALLING>; 29 | + }; 30 | }; 31 | 32 | i2c1: i2c@f0018000 { 33 | -------------------------------------------------------------------------------- /Chapter09/BB-ADC-MCP322-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-ADC-MCP322"; 9 | 10 | /* The version */ 11 | version = "00A0"; 12 | 13 | fragment@0 { 14 | target = <&i2c1>; 15 | 16 | __overlay__ { 17 | #address-cells = <1>; 18 | #size-cells = <0>; 19 | status = "okay"; 20 | 21 | /* Set the desired clock frequency */ 22 | clock-frequency = <400000>; 23 | 24 | /* Define the ADC device as based on mcp3221 25 | * and with I2C address 0x4d 26 | */ 27 | adc: adc@4d { 28 | compatible = "mcp3221"; 29 | reg = <0x4d>; 30 | }; 31 | }; 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /Chapter09/BB-EEPROM-A24-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-EEPROM-A24"; 9 | 10 | /* The version */ 11 | version = "00A0"; 12 | 13 | fragment@0 { 14 | target = <&i2c1>; 15 | 16 | __overlay__ { 17 | #address-cells = <1>; 18 | #size-cells = <0>; 19 | status = "okay"; 20 | 21 | /* Set the desired clock frequency */ 22 | clock-frequency = <400000>; 23 | 24 | /* Define the EEPROM device as based on at24c256 25 | * and with I2C address 0x50 26 | */ 27 | eeprom: eeprom@50 { 28 | compatible = "at24,24c02"; 29 | reg = <0x50>; 30 | }; 31 | }; 32 | }; 33 | }; 34 | -------------------------------------------------------------------------------- /Chapter09/BB-IOEXP-MCP23-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-IOEXP-MCP23"; 9 | 10 | /* The version */ 11 | version = "00A0"; 12 | 13 | fragment@0 { 14 | target = <&i2c1>; 15 | 16 | __overlay__ { 17 | #address-cells = <1>; 18 | #size-cells = <0>; 19 | status = "okay"; 20 | 21 | /* Set the desired clock frequency */ 22 | clock-frequency = <400000>; 23 | 24 | /* Define the IO Expander device as based on mcp23xxx 25 | * and with I2C address 0x20 26 | */ 27 | gpio: gpio@20 { 28 | compatible = "microchip,mcp23008"; 29 | reg = <0x20>; 30 | gpio-controller; 31 | #gpio-cells = <2>; 32 | }; 33 | }; 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /Chapter09/README.md: -------------------------------------------------------------------------------- 1 | Chapter 9 - Inter Integrated Circuits - I2C 2 | =========================================== 3 | 4 | Here the code from chapter 9 - "Inter Integrated Circuits - I2C" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some kernel configuration files (DTS) useful to enable the I2C devices 9 | presented into the book. Also some programming examples about how to get access 10 | to a I2C device from the user-space are present. 11 | 12 | See the URL 13 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 14 | for further info. 15 | -------------------------------------------------------------------------------- /Chapter09/i2c_dac/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = i2c_dac 2 | 3 | CFLAGS := -Wall -O2 -D_GNU_SOURCE 4 | 5 | all: $(TARGET) 6 | 7 | clean: 8 | rm -rf $(TARGET) 9 | 10 | phony: all clean 11 | -------------------------------------------------------------------------------- /Chapter09/i2c_dac/i2c_dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define NAME program_invocation_short_name 13 | 14 | #define I2C_DEV "/dev/i2c-1" 15 | #define I2C_SLAVE_ADDR (0x90 >> 1) 16 | 17 | static void reg2value(unsigned char b1, unsigned char b2, int *val) 18 | { 19 | *val = (b1 << 2) | (b2 >> 6); 20 | } 21 | 22 | static void value2reg(int val, unsigned char *b1, unsigned char *b2) 23 | { 24 | *b1 = val >> 2; 25 | *b2 = val << 6; 26 | } 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | int fd; 31 | int val; 32 | unsigned char wbuf[] = { 33 | 0, /* register address */ 34 | 0, /* data 1st byte */ 35 | 0, /* data 2nd byte */ 36 | }; 37 | unsigned char rbuf[] = { 38 | 0, /* data 1st byte */ 39 | 0, /* data 2nd byte */ 40 | }; 41 | int ret; 42 | 43 | /* Open the I2C bus */ 44 | ret = open(I2C_DEV, O_RDWR); 45 | if (ret < 0) { 46 | fprintf(stderr, "%s: unable to open the i2c bus device %s\n", 47 | NAME, I2C_DEV); 48 | exit(1); 49 | } 50 | fd = ret; 51 | 52 | /* Select the I2C bus to talk with */ 53 | ret = ioctl(fd, I2C_SLAVE, I2C_SLAVE_ADDR); 54 | if (ret < 0) { 55 | fprintf(stderr, "%s: cannot acquire access to address 0x%x\n", 56 | NAME, I2C_SLAVE_ADDR); 57 | exit(1); 58 | } 59 | 60 | /* 61 | * Check the command line in order to know if we must 62 | * read or write data 63 | */ 64 | if (argc == 1) { /* must read */ 65 | ret = read(fd, rbuf, sizeof(rbuf)); 66 | if (ret != sizeof(rbuf)) { 67 | fprintf(stderr, "%s: failed to read: %m\n", NAME); 68 | exit(1); 69 | } 70 | 71 | /* Convert the just read data to a readable form */ 72 | reg2value(rbuf[0], rbuf[1], &val); 73 | 74 | printf("%d\n", val); 75 | } else { /* must write */ 76 | ret = sscanf(argv[1], "%d", &val); 77 | if (ret !=1 || val < 0 || val >= (1 << 10)) { 78 | fprintf(stderr, "%s: invalid value! Must be in [0:%d]\n", 79 | NAME, (1 << 10) - 1); 80 | exit(-1); 81 | } 82 | 83 | /* Convert the user's value into a suitable form for the DAC */ 84 | value2reg(val, &wbuf[1], &wbuf[2]); 85 | 86 | /* Write the data to the device */ 87 | ret = write(fd, wbuf, sizeof(wbuf)); 88 | if (ret != sizeof(wbuf)) { 89 | fprintf(stderr, "%s: failed to write: %m\n", NAME); 90 | exit(1); 91 | } 92 | } 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /Chapter09/i2c_temp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import smbus 7 | 8 | # Defines 9 | BUS = 0 10 | ADDRESS = 0x5a 11 | REG = 0x07 12 | 13 | # Open the I2C bus /dev/i2c-X 14 | bus = smbus.SMBus(BUS) 15 | 16 | # Read a single register 17 | raw_value = bus.read_word_data(ADDRESS, REG) 18 | 19 | # Convert the data in C degrees and then display it 20 | degrees = raw_value * .02 - 273.15 21 | print("%0.2f" % degrees) 22 | -------------------------------------------------------------------------------- /Chapter10/A5D3-TTY-SC16IS7-dts.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..f4621a8 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -29,6 +29,12 @@ 6 | main_xtal { 7 | clock-frequency = <12000000>; 8 | }; 9 | + 10 | + sc16is7xx_ck: sc16is7xx_ck { 11 | + compatible = "fixed-clock"; 12 | + #clock-cells = <0>; 13 | + clock-frequency = <14745600>; 14 | + }; 15 | }; 16 | 17 | ahb { 18 | @@ -159,6 +165,15 @@ 19 | spi1: spi@f8008000 { 20 | cs-gpios = <&pioC 25 0>; 21 | status = "okay"; 22 | + 23 | + sc16is750: sc16is750@0 { 24 | + compatible = "nxp,sc16is750"; 25 | + reg = <0>; 26 | + spi-max-frequency = <15000000>; 27 | + 28 | + clocks = <&sc16is7xx_ck>; 29 | + interrupts-extended = <&pioA 22 IRQ_TYPE_EDGE_FALLING>; 30 | + }; 31 | }; 32 | 33 | adc0: adc@f8018000 { 34 | -------------------------------------------------------------------------------- /Chapter10/A5D3-digital-IO-spi.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..0544120 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -157,8 +157,20 @@ 6 | }; 7 | 8 | spi1: spi@f8008000 { 9 | - cs-gpios = <&pioC 25 0>; 10 | + cs-gpios = <&pioC 25 0>, <&pioC 16 0>; 11 | status = "okay"; 12 | + 13 | + vni8200xp@0 { 14 | + compatible = "spidev"; 15 | + reg = <0>; 16 | + spi-max-frequency = <1000000>; 17 | + }; 18 | + 19 | + clt01_38sq7@1 { 20 | + compatible = "spidev"; 21 | + reg = <1>; 22 | + spi-max-frequency = <1000000>; 23 | + }; 24 | }; 25 | 26 | adc0: adc@f8018000 { 27 | -------------------------------------------------------------------------------- /Chapter10/README.md: -------------------------------------------------------------------------------- 1 | Chapter 10 - Serial Peripheral Interface - SPI 2 | ============================================== 3 | 4 | Here the code from chapter 10 - "Serial Peripheral Interface - SPI" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some kernel configuration files (DTS) useful to enable the SPI devices 9 | presented into the book. Also some programming examples about how to get access 10 | to a SPI device from the user-space are present. 11 | 12 | See the URL 13 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 14 | for further info. 15 | -------------------------------------------------------------------------------- /Chapter10/digital.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import getopt 7 | import spidev 8 | 9 | NAME = os.path.basename(sys.argv[0]) 10 | 11 | debug = 0 12 | 13 | # 14 | # Local functions 15 | # 16 | 17 | def error(*objs): 18 | print(NAME, ": ", *objs, file = sys.stderr) 19 | 20 | def info(*objs): 21 | print(NAME, ": ", *objs) 22 | 23 | def dbg(*objs): 24 | if (debug): 25 | print(NAME, ": ", *objs) 26 | 27 | def do_write(data): 28 | spi = spidev.SpiDev() 29 | spi.open(32765, 0) # the SPI device for output 30 | 31 | # Do some SPI settings 32 | spi.max_speed_hz = 1000000 33 | spi.bits_per_word = 16 34 | 35 | # Compute the checksum 36 | p0 = data ^ (data >> 1) 37 | p0 = p0 ^ (p0 >> 2) 38 | p0 = p0 ^ (p0 >> 4) 39 | p0 = p0 & 1; 40 | p1 = data ^ (data >> 2) 41 | p1 = p1 ^ (p1 >> 4) 42 | p2 = p1 & 1 43 | p1 = p1 & 2 44 | p1 = p1 >> 1 45 | np0 = not p0 46 | tmp = (p2 << 3) | (p1 << 2) | (p0 << 1) | np0 47 | tmp = 0x01 48 | dbg("p2.p1.p0.np0=0x%01x" % (tmp)) 49 | 50 | # Do the write 51 | dbg("write=0x%04x" % ((data << 8) | tmp)) 52 | data = spi.xfer2([tmp, data]) 53 | 54 | # Decode answer 55 | faults = data[1] 56 | ok = 1 if data[0] & 0b10000000 else 0 57 | twarn = 0 if data[0] & 0b01000000 else 1 58 | pc = 1 if data[0] & 0b00100000 else 0 59 | pg = 0 if data[0] & 0b00010000 else 1 60 | p = data[0] & 0b00001111 61 | dbg("faults=0x%02x ok=%d twarn=%d pc=%d pg=%d p2.p1.p0.np0=0x%01x" % 62 | (faults, ok, twarn, pc, pg, p)) 63 | 64 | spi.close() 65 | 66 | def do_read(): 67 | spi = spidev.SpiDev() 68 | spi.open(32765, 1) # the SPI device for input 69 | 70 | # Do some SPI settings 71 | spi.max_speed_hz = 1000000 72 | spi.bits_per_word = 16 73 | 74 | # Do the read 75 | data = spi.xfer2([0, 0]) 76 | dbg("read=0x%04x" % ((data[1] << 8) | data[0])) 77 | 78 | spi.close() 79 | 80 | # Compute the checksum and extract alarms 81 | uva = 1 if data[0] & 0b10000000 else 0 82 | ota = 1 if data[0] & 0b01000000 else 0 83 | pc = (data[0] >> 2) & 0b00001111 84 | ok = 1 if (data[0] & 0b00000011) == 1 else 0 85 | 86 | dbg("inputs=0x%02x uva=%d ota=%d pc=0x%x ok=%d" % 87 | (data[1], uva, ota, pc, ok)) 88 | 89 | return data[1] 90 | 91 | def usage(): 92 | print("usage: ", NAME, " [-h|--help -d|--debug] w | r", 93 | file = sys.stderr) 94 | sys.exit(2); 95 | 96 | # 97 | # Main 98 | # 99 | 100 | try: 101 | opts, args = getopt.getopt(sys.argv[1:], "hd", ["help", "--debug"]) 102 | except getopt.GetoptError, err: 103 | # print help information and exit: 104 | error(str(err)) 105 | usage() 106 | 107 | for o, a in opts: 108 | if o in ("-h", "--help"): 109 | usage() 110 | elif o in ("-d", "--debug"): 111 | debug = 1 112 | else: 113 | assert False, "unhandled option" 114 | 115 | # Check command line 116 | if len(args) < 1: 117 | usage() 118 | 119 | # Check the user inputs 120 | cmd = args[0] 121 | if cmd == "w": 122 | if len(args) < 1: 123 | error("missing parameter!") 124 | sys.exit(1) 125 | try: 126 | data = int(args[1], 16) 127 | except ValueError, err: 128 | error("invalid number for :", args[1]) 129 | sys.exit(1) 130 | if data < 0 or data > 65535: 131 | error("invalid number for port, must be [0, 65535]:", args[0]) 132 | sys.exit(1) 133 | 134 | do_write(data) 135 | elif cmd == "r": 136 | data = do_read() 137 | 138 | print("0x%02x" % data) 139 | else: 140 | error("invalid command, must be [w,r]", args[0]) 141 | -------------------------------------------------------------------------------- /Chapter10/imx6qdl-wandboard-spidev.dtsi.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2 | index 9e096d8..36cce9a 100644 3 | --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 4 | +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 5 | @@ -147,6 +147,16 @@ 6 | >; 7 | }; 8 | 9 | + pinctrl_ecspi1_1: ecspi1grp-1 { 10 | + fsl,pins = < 11 | + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 12 | + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 13 | + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 14 | + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x000f0b0 15 | + MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x000f0b0 16 | + >; 17 | + }; 18 | + 19 | pinctrl_uart1: uart1grp { 20 | fsl,pins = < 21 | MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 22 | @@ -224,6 +234,26 @@ 23 | status = "okay"; 24 | }; 25 | 26 | +&ecspi1 { 27 | + fsl,spi-num-chipselects = <2>; 28 | + cs-gpios = <&gpio2 30 0>, <&gpio4 10 0>; 29 | + pinctrl-names = "default"; 30 | + pinctrl-0 = <&pinctrl_ecspi1_1>; 31 | + status = "okay"; 32 | + 33 | + spidev@0 { 34 | + compatible = "spidev"; 35 | + reg = <0>; 36 | + spi-max-frequency = <1000000>; 37 | + }; 38 | + 39 | + spidev@1 { 40 | + compatible = "spidev"; 41 | + reg = <1>; 42 | + spi-max-frequency = <1000000>; 43 | + }; 44 | +}; 45 | + 46 | &uart1 { 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&pinctrl_uart1>; 49 | -------------------------------------------------------------------------------- /Chapter10/spi_thermo/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = spi_thermo 2 | 3 | CFLAGS := -Wall -O2 -D_GNU_SOURCE 4 | 5 | all: $(TARGET) 6 | 7 | clean: 8 | rm -rf $(TARGET) 9 | 10 | phony: all clean 11 | -------------------------------------------------------------------------------- /Chapter10/spi_thermo/spi_thermo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define NAME program_invocation_short_name 16 | 17 | #define SPI_DEV "/dev/spidev1.0" 18 | 19 | #define THERMO_SHIFT 18 20 | #define THERMO_MASK ((1 << 15) - 1) 21 | #define THERMO_SIGN (1 << 31) 22 | #define FAULT_FLAG (1 << 16) 23 | 24 | int main(int argc, char **argv) 25 | { 26 | int fd; 27 | unsigned int data; 28 | float t; 29 | int ret; 30 | 31 | /* Open the SPI bus device connected to the thermocouple chip */ 32 | fd = open(SPI_DEV, O_RDWR); 33 | if (fd < 0) { 34 | fprintf(stderr, "%s: cannot get access to SPI bus\n", NAME); 35 | exit(1); 36 | } 37 | 38 | /* Read the 32-bit data */ 39 | ret = read(fd, &data, 4); 40 | if (ret < 0) { 41 | fprintf(stderr, "%s: cannot read data from SPI device\n", NAME); 42 | exit(1); 43 | } 44 | if (ret != 4) { 45 | fprintf(stderr, "%s: short read\n", NAME); 46 | exit(1); 47 | } 48 | 49 | /* Adapt the endianness to the current host */ 50 | data = be32toh(data); 51 | 52 | /* Check for errors */ 53 | if (data & FAULT_FLAG) { 54 | fprintf(stderr, "%s: invalid emperature data\n", NAME); 55 | exit(1); 56 | } 57 | 58 | /* Get the temperature data */ 59 | t = (data >> THERMO_SHIFT) & THERMO_MASK; 60 | t /= 4; 61 | if (data & THERMO_SIGN) 62 | t = -t; 63 | 64 | printf("%.2f\n", t); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /Chapter11/BB-W1-GPIO-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-W1-GPIO"; 9 | 10 | /* The version */ 11 | version = "00A0"; 12 | 13 | /* Define the pins usage */ 14 | exclusive-use = 15 | /* the pin header P8 uses */ 16 | "P8.11", 17 | /* Hardware IP cores in use */ 18 | "gpio1_13"; 19 | 20 | fragment@0 { 21 | target = <&am33xx_pinmux>; 22 | 23 | __overlay__ { 24 | bb_w1_pins: pinmux_bb_w1_pins { 25 | pinctrl-single,pins = <0x34 0x37>; 26 | }; 27 | }; 28 | }; 29 | 30 | fragment@1 { 31 | target = <&ocp>; 32 | 33 | __overlay__ { 34 | #address-cells = <1>; 35 | #size-cell = <0>; 36 | status = "okay"; 37 | 38 | /* Setup the pins */ 39 | pinctrl-names = "default"; 40 | pinctrl-0 = <&bb_w1_pins>; 41 | 42 | /* Define the new one-wire master as based on w1-gpio 43 | * and using GPIO1_13 44 | */ 45 | onewire@0 { 46 | compatible = "w1-gpio"; 47 | gpios = <&gpio1 13 0>; 48 | }; 49 | }; 50 | }; 51 | }; 52 | -------------------------------------------------------------------------------- /Chapter11/README.md: -------------------------------------------------------------------------------- 1 | Chapter 11 - 1-Wire - W1 2 | ======================== 3 | 4 | Here the code from chapter 11 - "1-Wire - W1" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here is a kernel configuration files (DTS) useful to enable an emulated 1-Wire 9 | controller by using a GPIO. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter12/README.md: -------------------------------------------------------------------------------- 1 | Chapter 12 - Ethernet network device - ETH 2 | ========================================== 3 | 4 | Here the code from chapter 12 - "Ethernet network device - ETH" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here is an example of a client/server application. 9 | 10 | See the URL 11 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 12 | for further info. 13 | -------------------------------------------------------------------------------- /Chapter12/tcp_cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import getopt 7 | import string 8 | import socket 9 | 10 | NAME = os.path.basename(sys.argv[0]) 11 | 12 | # 13 | # Local functions 14 | # 15 | 16 | def error(*objs): 17 | print(NAME, ": ", *objs, file = sys.stderr) 18 | 19 | def info(*objs): 20 | print(NAME, ": ", *objs) 21 | 22 | def usage(): 23 | print("usage: ", NAME, " [-h]
", file = sys.stderr) 24 | sys.exit(2); 25 | 26 | # 27 | # Main 28 | # 29 | 30 | try: 31 | opts, args = getopt.getopt(sys.argv[1:], "h", 32 | ["help"]) 33 | except getopt.GetoptError, err: 34 | # Print help information and exit: 35 | error(str(err)) 36 | usage() 37 | 38 | for o, a in opts: 39 | if o in ("-h", "--help"): 40 | usage() 41 | else: 42 | assert False, "unhandled option" 43 | 44 | # Check command line 45 | if len(args) < 2: 46 | usage() 47 | 48 | # Check the user inputs 49 | host = args[0] 50 | try: 51 | port = int(args[1]) 52 | except ValueError, err: 53 | error("invalid number for :", args[1]) 54 | sys.exit(1) 55 | if port < 0 or port > 65535: 56 | error("invalid number for port, must be [0, 65535]:", args[0]) 57 | sys.exit(1) 58 | 59 | # Create a TCP/IP socket object 60 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 61 | 62 | # Connect with the server 63 | info("starting new connection...") 64 | s.connect((host, port)) 65 | 66 | # Print the server's hello message 67 | info("server says:", s.recv(1024)) 68 | 69 | # Close the connection 70 | s.close() 71 | info("connection closed!") 72 | -------------------------------------------------------------------------------- /Chapter12/tcp_srv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import getopt 7 | import string 8 | import socket 9 | 10 | NAME = os.path.basename(sys.argv[0]) 11 | 12 | host = "" # the empty string is treat as INADDR_ANY 13 | 14 | 15 | # 16 | # Local functions 17 | # 18 | 19 | def error(*objs): 20 | print(NAME, ": ", *objs, file = sys.stderr) 21 | 22 | def info(*objs): 23 | print(NAME, ": ", *objs) 24 | 25 | def usage(): 26 | print("usage: ", NAME, " [-h] ", file = sys.stderr) 27 | sys.exit(2); 28 | 29 | # 30 | # Main 31 | # 32 | 33 | try: 34 | opts, args = getopt.getopt(sys.argv[1:], "h", 35 | ["help"]) 36 | except getopt.GetoptError, err: 37 | # Print help information and exit: 38 | error(str(err)) 39 | usage() 40 | 41 | for o, a in opts: 42 | if o in ("-h", "--help"): 43 | usage() 44 | else: 45 | assert False, "unhandled option" 46 | 47 | # Check command line 48 | if len(args) < 1: 49 | usage() 50 | 51 | # Check the user input 52 | try: 53 | port = int(args[0]) 54 | except ValueError, err: 55 | error("invalid number for :", args[0]) 56 | sys.exit(1) 57 | if port < 0 or port > 65535: 58 | error("invalid number for port, must be [0, 65535]:", args[0]) 59 | sys.exit(1) 60 | 61 | # Create a TCP/IP socket object 62 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 63 | s.setsockopt(socket.SOL_SOCKET, 64 | socket.SO_REUSEADDR, 1) # avoid error: Address already in use 65 | server_address = (host, port) 66 | s.bind(server_address) 67 | info("starting up on %s port %s" % s.getsockname()) 68 | 69 | # Now we can listen for an incoming client connection 70 | s.listen(5) 71 | 72 | # The main loop 73 | while True: 74 | info("waiting for new connection...") 75 | 76 | # Establish connection with the client 77 | c, addr = s.accept() 78 | info("got connection from ", addr) 79 | 80 | # Send back an hello message 81 | c.send("Thank you for connecting!\n") 82 | 83 | # Close the connection 84 | c.close() 85 | info("connection closed!") 86 | -------------------------------------------------------------------------------- /Chapter13/README.md: -------------------------------------------------------------------------------- 1 | Chapter 13 - Wireless Network Device - WLAN 2 | =========================================== 3 | 4 | Here the code from chapter 13 - "Wireless Network Device - WLAN" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here is an example of HostAPd's configuration file and udhcpd's configuration 9 | file presented into the book. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter13/hostapd.conf: -------------------------------------------------------------------------------- 1 | ssid=BBBAccessPoint 2 | wpa_passphrase=BBBpassphrase 3 | 4 | ctrl_interface=/var/run/hostapd 5 | interface=wlx801f028f758d 6 | bridge=br0 7 | driver=nl80211 8 | hw_mode=g 9 | channel=6 10 | wpa=2 11 | 12 | beacon_int=100 13 | hw_mode=g 14 | ieee80211n=1 15 | wme_enabled=1 16 | ht_capab=[SHORT-GI-20][SHORT-GI-40][HT40+] 17 | wpa_key_mgmt=WPA-PSK 18 | wpa_pairwise=CCMP 19 | max_num_sta=8 20 | wpa_group_rekey=86400 21 | -------------------------------------------------------------------------------- /Chapter13/udhcpd.conf.br0: -------------------------------------------------------------------------------- 1 | # udhcpd configuration file for bridging 2 | 3 | start 192.168.32.100 4 | end 192.168.32.200 5 | 6 | interface br0 7 | max_leases 10 8 | 9 | option dns 8.8.8.8 8.8.4.4 10 | option subnet 255.255.255.0 11 | option router 192.168.32.41 12 | option lease 864000 # 10 days of seconds 13 | -------------------------------------------------------------------------------- /Chapter14/BB-DCAN1-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 6 | 7 | /* Identification string */ 8 | part-number = "BB-DCAN1-00A0"; 9 | 10 | /* Define the pins usage */ 11 | exclusive-use = 12 | /* the pin header P9 uses */ 13 | "P9.24", 14 | "P9.26", 15 | /* Hardware IP cores in use */ 16 | "uart1"; 17 | 18 | fragment@0 { 19 | target = <&am33xx_pinmux>; 20 | 21 | __overlay__ { 22 | dcan1_pins_s0: dcan1_pins_s0 { 23 | pinctrl-single,pins = < 24 | 0x180 0x12 /* d_can1_tx, SLEWCTRL_FAST | INPUT_PULLUP | MODE2 */ 25 | 0x184 0x32 /* d_can1_rx, SLEWCTRL_FAST | RECV_ENABLE | INPUT_PULLUP | MODE2 */ 26 | >; 27 | }; 28 | }; 29 | }; 30 | 31 | fragment@1 { 32 | target = <&dcan1>; 33 | 34 | __overlay__ { 35 | #address-cells = <1>; 36 | #size-cells = <0>; 37 | 38 | status = "okay"; 39 | pinctrl-names = "default"; 40 | pinctrl-0 = <&dcan1_pins_s0>; 41 | }; 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /Chapter14/README.md: -------------------------------------------------------------------------------- 1 | Chapter 14 - Controller Area Network - CAN 2 | ========================================== 3 | 4 | Here the code from chapter 14 - "Controller Area Network - CAN" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some DTS files to enable CAN controllers support and a SocketCAN 9 | exmaple code. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter14/imx6qdl-wandboard-mcp2515.dtsi.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2 | index 9e096d8..bc83ffe 100644 3 | --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 4 | +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 5 | @@ -36,6 +36,16 @@ 6 | }; 7 | }; 8 | 9 | + clocks { 10 | + clk_4MHz: clk@1 { 11 | + compatible = "fixed-clock"; 12 | + reg = <1>; 13 | + #clock-cells = <0>; 14 | + clock-frequency = <4000000>; 15 | + clock-output-names = "clk-4MHz"; 16 | + }; 17 | + }; 18 | + 19 | sound { 20 | compatible = "fsl,imx6-wandboard-sgtl5000", 21 | "fsl,imx-audio-sgtl5000"; 22 | @@ -147,6 +157,21 @@ 23 | >; 24 | }; 25 | 26 | + pinctrl_ecspi1_1: ecspi1grp-1 { 27 | + fsl,pins = < 28 | + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 29 | + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 30 | + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 31 | + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x000f0b0 32 | + >; 33 | + }; 34 | + 35 | + pinctrl_can_int: cangrp-1 { 36 | + fsl,pins = < 37 | + MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x80000000 38 | + >; 39 | + }; 40 | + 41 | pinctrl_uart1: uart1grp { 42 | fsl,pins = < 43 | MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 44 | @@ -224,6 +249,25 @@ 45 | status = "okay"; 46 | }; 47 | 48 | +&ecspi1 { 49 | + fsl,spi-num-chipselects = <1>; 50 | + cs-gpios = <&gpio2 30 0>; 51 | + pinctrl-names = "default"; 52 | + pinctrl-0 = <&pinctrl_ecspi1_1>, <&pinctrl_can_int>; 53 | + status = "okay"; 54 | + 55 | + can@0 { 56 | + compatible = "microchip,mcp2515"; 57 | + reg = <0>; 58 | + spi-max-frequency = <1000000>; 59 | + 60 | + clocks = <&clk_4MHz>; 61 | + 62 | + interrupt-parent = <&gpio3>; 63 | + interrupts = <27 IRQ_TYPE_EDGE_FALLING>; 64 | + }; 65 | +}; 66 | + 67 | &uart1 { 68 | pinctrl-names = "default"; 69 | pinctrl-0 = <&pinctrl_uart1>; 70 | -------------------------------------------------------------------------------- /Chapter14/socketcan/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = socketcan_send 2 | 3 | CFLAGS = -Wall -O2 -D_GNU_SOURCE 4 | 5 | all: $(TARGET) 6 | 7 | clean: 8 | rm -rf $(TARGET) 9 | -------------------------------------------------------------------------------- /Chapter14/socketcan/socketcan_send.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #define NAME program_invocation_short_name 16 | 17 | void usage(void) 18 | { 19 | fprintf(stderr, "usage: %s \n", NAME); 20 | 21 | exit(-1); 22 | } 23 | 24 | /* 25 | * Main 26 | */ 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | int s; 31 | int n; 32 | char *ifname; 33 | struct sockaddr_can addr; 34 | struct can_frame frame; 35 | struct ifreq ifr; 36 | int ret; 37 | 38 | /* Check command line */ 39 | if (argc < 1) 40 | usage(); 41 | ifname = argv[1]; 42 | 43 | /* Open the PF_CAN socket */ 44 | s = socket(PF_CAN, SOCK_RAW, CAN_RAW); 45 | if (s < 0) { 46 | perror("Error while opening socket"); 47 | exit(-1); 48 | } 49 | 50 | /* Find the CAN device */ 51 | strcpy(ifr.ifr_name, ifname); 52 | ret = ioctl(s, SIOCGIFINDEX, &ifr); 53 | if (ret < 0) { 54 | perror("ioctl"); 55 | exit(-1); 56 | } 57 | printf("%s: %s at index %d\n", NAME, ifname, ifr.ifr_ifindex); 58 | 59 | /* Bind the socket */ 60 | addr.can_family = AF_CAN; 61 | addr.can_ifindex = ifr.ifr_ifindex; 62 | ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); 63 | if (ret < 0) { 64 | perror("bind"); 65 | exit(-1); 66 | } 67 | 68 | /* Fill the frame data */ 69 | frame.can_id = 0x123; 70 | frame.can_dlc = 2; 71 | frame.data[0] = 0x11; 72 | frame.data[1] = 0x22; 73 | 74 | /* Send the frame */ 75 | n = write(s, &frame, sizeof(struct can_frame)); 76 | if (ret < 0) { 77 | perror("write"); 78 | exit(-1); 79 | } 80 | printf("%s: wrote %d bytes\n", NAME, n); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /Chapter15/README.md: -------------------------------------------------------------------------------- 1 | Chapter 15 - Sound devices - SND 2 | ================================ 3 | 4 | Here the code from chapter 15 - "Sound devices - SND" of the book 5 | "GNU/Linux Rapid Embedded Programming" written by Rodolfo Giometti 6 | and published by Packt Publishing (ISBN 978-1-78646-180-3). 7 | 8 | Here are some sample audio files used in the book and a patch to fix up an audio 9 | kernel driver. 10 | 11 | See the URL 12 | FIXME: https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints 13 | for further info. 14 | -------------------------------------------------------------------------------- /Chapter15/audio-codec-wm8731.patch: -------------------------------------------------------------------------------- 1 | diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 2 | index ff888d2..03a4c64 100644 3 | --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts 4 | +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts 5 | @@ -61,6 +61,12 @@ 6 | status = "okay"; 7 | }; 8 | 9 | + ssc0: ssc@f0008000 { 10 | + pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; 11 | + status = "okay"; 12 | + }; 13 | + 14 | + 15 | can0: can@f000c000 { 16 | status = "okay"; 17 | }; 18 | @@ -68,6 +74,11 @@ 19 | i2c0: i2c@f0014000 { 20 | pinctrl-0 = <&pinctrl_i2c0_pu>; 21 | status = "okay"; 22 | + 23 | + wm8731: wm8731@1a { 24 | + compatible = "wm8731"; 25 | + reg = <0x1a>; 26 | + }; 27 | }; 28 | 29 | i2c1: i2c@f0018000 { 30 | @@ -333,4 +344,17 @@ 31 | gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; 32 | }; 33 | }; 34 | + 35 | + sound { 36 | + compatible = "atmel,sam9x5-wm8731-audio"; 37 | + atmel,model = "wm8731 @ SAMA5D3 Xplained"; 38 | + atmel,audio-routing = 39 | + "Headphone Jack", "RHPOUT", 40 | + "Headphone Jack", "LHPOUT", 41 | + "LLINEIN", "Line In Jack", 42 | + "RLINEIN", "Line In Jack"; 43 | + 44 | + atmel,ssc-controller = <&ssc0>; 45 | + atmel,audio-codec = <&wm8731>; 46 | + }; 47 | }; 48 | -------------------------------------------------------------------------------- /Chapter15/tone-sine-1000hz.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter15/tone-sine-1000hz.m4a -------------------------------------------------------------------------------- /Chapter15/tone-sine-1000hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter15/tone-sine-1000hz.mp3 -------------------------------------------------------------------------------- /Chapter15/tone-sine-1000hz.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter15/tone-sine-1000hz.wav -------------------------------------------------------------------------------- /Chapter16/input_uvc.patch: -------------------------------------------------------------------------------- 1 | --- plugins/input_uvc/input_uvc.c (revision 174) 2 | +++ plugins/input_uvc/input_uvc.c (working copy) 3 | @@ -405,9 +405,13 @@ 4 | if(pcontext->videoIn->formatIn == V4L2_PIX_FMT_YUYV) { 5 | DBG("compressing frame from input: %d\n", (int)pcontext->id); 6 | pglobal->in[pcontext->id].size = compress_yuyv_to_jpeg(pcontext->videoIn, pglobal->in[pcontext->id].buf, pcontext->videoIn->framesizeIn, gquality); 7 | + /* copy this frame's timestamp to user space */ 8 | + pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp; 9 | } else { 10 | DBG("copying frame from input: %d\n", (int)pcontext->id); 11 | - pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused); 12 | + pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->tmpbytesused); 13 | + /* copy this frame's timestamp to user space */ 14 | + pglobal->in[pcontext->id].timestamp = pcontext->videoIn->tmptimestamp; 15 | } 16 | 17 | #if 0 18 | @@ -418,8 +422,6 @@ 19 | prev_size = global->size; 20 | #endif 21 | 22 | - /* copy this frame's timestamp to user space */ 23 | - pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp; 24 | 25 | /* signal fresh_frame */ 26 | pthread_cond_broadcast(&pglobal->in[pcontext->id].db_update); 27 | Index: plugins/input_uvc/v4l2uvc.c 28 | =================================================================== 29 | --- plugins/input_uvc/v4l2uvc.c (revision 174) 30 | +++ plugins/input_uvc/v4l2uvc.c (working copy) 31 | @@ -450,6 +450,8 @@ 32 | */ 33 | 34 | memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused); 35 | + vd->tmpbytesused = vd->buf.bytesused; 36 | + vd->tmptimestamp = vd->buf.timestamp; 37 | 38 | if(debug) 39 | fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused); 40 | Index: plugins/input_uvc/v4l2uvc.h 41 | =================================================================== 42 | --- plugins/input_uvc/v4l2uvc.h (revision 174) 43 | +++ plugins/input_uvc/v4l2uvc.h (working copy) 44 | @@ -28,6 +28,7 @@ 45 | 46 | 47 | #include 48 | +#include 49 | #include 50 | #include 51 | #include 52 | @@ -105,6 +106,8 @@ 53 | int framecount; 54 | int recordstart; 55 | int recordtime; 56 | + uint32_t tmpbytesused; 57 | + struct timeval tmptimestamp; 58 | }; 59 | 60 | /* context of each camera thread */ 61 | -------------------------------------------------------------------------------- /Chapter17/mq2.log: -------------------------------------------------------------------------------- 1 | 804.931641 1478100875444651544 2 | 796.142578 1478100875944588271 3 | 803.466797 1478100876444588392 4 | 804.199219 1478100876944585786 5 | 792.480469 1478100877444585120 6 | 802.734375 1478100877944584210 7 | 799.804688 1478100878444583301 8 | 794.677734 1478100878944582816 9 | 799.072266 1478100879444581483 10 | 800.537109 1478100879944583119 11 | 796.875000 1478100880444578392 12 | 799.804688 1478100880944578331 13 | 801.269531 1478100881444580331 14 | 798.339844 1478100881944576088 15 | 867.919922 1478100882444575603 16 | 1676.513672 1478100882944574634 17 | 2184.814453 1478100883444573300 18 | 2302.001953 1478100883944572391 19 | 2330.566406 1478100884444570997 20 | 2334.960938 1478100884944573360 21 | 2310.791016 1478100885444569663 22 | 2277.832031 1478100885944568936 23 | 2243.408203 1478100886444571239 24 | 2215.576172 1478100886944565966 25 | 2190.673828 1478100887444564996 26 | 2167.968750 1478100887944564027 27 | 2146.728516 1478100888444563057 28 | 2123.291016 1478100888944562693 29 | 2105.712891 1478100889444562087 30 | 2079.345703 1478100889944560632 31 | 2057.373047 1478100890444559541 32 | 2033.935547 1478100890944558996 33 | 2011.230469 1478100891444557905 34 | 1987.792969 1478100891944556389 35 | 1963.623047 1478100892444556208 36 | 1948.242188 1478100892944556026 37 | 1918.945312 1478100893444554389 38 | 1897.705078 1478100893944553722 39 | 1873.535156 1478100894444553116 40 | 1856.689453 1478100894944551722 41 | 1831.054688 1478100895444550146 42 | 1814.941406 1478100895944550207 43 | 1792.968750 1478100896444548389 44 | 1772.460938 1478100896944548934 45 | 1751.220703 1478100897444546267 46 | 1729.248047 1478100897944545479 47 | 1711.669922 1478100898444543964 48 | 1692.626953 1478100898944544691 49 | 1675.048828 1478100899444542691 50 | 1661.132812 1478100899944541842 51 | 1650.146484 1478100900444540024 52 | 1627.441406 1478100900944539418 53 | 1610.595703 1478100901444538327 54 | 1593.750000 1478100901944537175 55 | 1590.820312 1478100902444536266 56 | 1562.255859 1478100902944535599 57 | 1549.072266 1478100903444534266 58 | 1535.888672 1478100903944533296 59 | 1521.240234 1478100904444534811 60 | 1508.056641 1478100904944531538 61 | 1491.943359 1478100905444530750 62 | 1481.689453 1478100905944529296 63 | 1465.576172 1478100906444528387 64 | 1458.984375 1478100906944526932 65 | 1440.673828 1478100907444525962 66 | 1433.349609 1478100907944525659 67 | 1422.363281 1478100908444524507 68 | 1408.447266 1478100908944524629 69 | 1395.996094 1478100909444525416 70 | 1385.009766 1478100909944522750 71 | 1368.896484 1478100910444521234 72 | 1359.375000 1478100910944520083 73 | 1357.177734 1478100911444519174 74 | 1335.937500 1478100911944518143 75 | 1330.810547 1478100912444526992 76 | 1320.556641 1478100912944516204 77 | 1307.373047 1478100913444514991 78 | 1302.978516 1478100913944515173 79 | 1291.259766 1478100914444513537 80 | 1286.865234 1478100914944512385 81 | 1292.724609 1478100915444511900 82 | 1277.343750 1478100915944510082 83 | 1256.103516 1478100916444509718 84 | 1248.779297 1478100916944508869 85 | 1235.595703 1478100917444507172 86 | 1235.595703 1478100917944506203 87 | 1223.144531 1478100918444505354 88 | 1217.285156 1478100918944505415 89 | 1209.228516 1478100919444503354 90 | 1196.777344 1478100919944502445 91 | 1192.382812 1478100920444501838 92 | 1186.523438 1478100920944500929 93 | 1182.861328 1478100921444499959 94 | 1174.072266 1478100921944498020 95 | 1168.212891 1478100922444497959 96 | 1161.621094 1478100922944497353 97 | 1146.972656 1478100923444495656 98 | 1145.507812 1478100923944495232 99 | 1141.113281 1478100924444493050 100 | 1133.789062 1478100924944491535 101 | -------------------------------------------------------------------------------- /Chapter17/mq2.plot: -------------------------------------------------------------------------------- 1 | set terminal png size 800,600 enhanced font "Helvetica,20" 2 | set output 'mq2.png' 3 | set xdata time 4 | set autoscale 5 | set nokey 6 | set grid lw 1 7 | show grid 8 | set xlabel "\nTime" 9 | set ylabel 'raw' 10 | set format x "%.9f" 11 | set xtics rotate 12 | plot "mq2.log" using ($2/1000000000):($1) with lines 13 | -------------------------------------------------------------------------------- /Chapter17/mq2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter17/mq2.png -------------------------------------------------------------------------------- /Chapter19/gsm/myisp: -------------------------------------------------------------------------------- 1 | # Set up the network's APN value. 2 | connect "/usr/sbin/chat -v -f /etc/chatscripts/gprs -T my_APN_value" 3 | 4 | # The GSM device 5 | /dev/ttyUSB0 6 | 7 | # Speed of the serial line. 8 | 115200 9 | 10 | # Assumes that your IP address is allocated dynamically by the ISP. 11 | noipdefault 12 | 13 | # Try to get the name server addresses from the ISP. 14 | usepeerdns 15 | 16 | # Use this connection as the default route to the internet. 17 | defaultroute 18 | 19 | # Makes PPPD "dial again" when the connection is lost. 20 | persist 21 | 22 | # Do not ask the remote to authenticate. 23 | noauth 24 | 25 | # No hardware flow control on the serial link 26 | nocrtscts 27 | 28 | # No modem control lines 29 | local 30 | 31 | # Enable debugging messages 32 | debug 33 | -------------------------------------------------------------------------------- /Chapter19/rfid/Makefile: -------------------------------------------------------------------------------- 1 | TARGETS = rfid_uhf 2 | 3 | CFLAGS = -Wall -O2 -D_GNU_SOURCE 4 | LDLIBS = -lcaenrfid 5 | 6 | all : $(TARGETS) 7 | 8 | clean : 9 | rm $(TARGETS) 10 | -------------------------------------------------------------------------------- /Chapter19/rfid/libavp.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter19/rfid/libavp.tgz -------------------------------------------------------------------------------- /Chapter19/rfid/libcaenrfid.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter19/rfid/libcaenrfid.tgz -------------------------------------------------------------------------------- /Chapter19/rfid/libmsgbuff.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter19/rfid/libmsgbuff.tgz -------------------------------------------------------------------------------- /Chapter19/rfid/rfid_uhf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #define NAME program_invocation_short_name 10 | 11 | int debug = 0; 12 | 13 | static char nibble2hex(char c) 14 | { 15 | switch (c) { 16 | case 0 ... 9: 17 | return '0' + c; 18 | 19 | case 0xa ... 0xf: 20 | return 'a' + (c - 10); 21 | } 22 | 23 | printf("got invalid data!\n"); 24 | return '\0'; 25 | } 26 | 27 | /* 28 | * Local functions 29 | */ 30 | 31 | char *bin2hex(uint8_t *data, size_t len) 32 | { 33 | char *str; 34 | int i; 35 | 36 | str = malloc(len * 2 + 1); 37 | if (!str) 38 | return NULL; 39 | 40 | for (i = 0; i < len; i++) { 41 | str[i * 2] = nibble2hex(data[i] >> 4); 42 | str[i * 2 + 1] = nibble2hex(data[i] & 0x0f); 43 | } 44 | str[i * 2] = '\0'; 45 | 46 | return str; 47 | } 48 | 49 | /* 50 | * Usage function 51 | */ 52 | 53 | void usage(void) 54 | { 55 | fprintf(stderr, "usage: %s \n", NAME); 56 | 57 | exit(-1); 58 | } 59 | 60 | /* 61 | * Main 62 | */ 63 | 64 | int main(int argc, char *argv[]) 65 | { 66 | int i; 67 | struct caenrfid_handle handle; 68 | char string[] = "Source_0"; 69 | struct caenrfid_tag *tag; 70 | size_t size; 71 | char *str; 72 | int ret; 73 | 74 | if (argc < 2) 75 | usage(); 76 | 77 | /* Start a new connection with the CAENRFIDD server */ 78 | ret = caenrfid_open(CAENRFID_PORT_RS232, argv[1], &handle); 79 | if (ret < 0) 80 | usage(); 81 | 82 | /* Set session "S2" for logical source 0 */ 83 | ret = caenrfid_set_srcconf(&handle, "Source_0", 84 | CAENRFID_SRC_CFG_G2_SESSION, 2); 85 | if (ret < 0) { 86 | fprintf(stderr, "cannot set session 2 (err=%d)\n", ret); 87 | exit(EXIT_FAILURE); 88 | } 89 | 90 | while (1) { 91 | /* Do the inventory */ 92 | ret = caenrfid_inventory(&handle, string, &tag, &size); 93 | if (ret < 0) { 94 | fprintf(stderr, "cannot get data (err=%d)\n", ret); 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | /* Report results */ 99 | for (i = 0; i < size; i++) { 100 | str = bin2hex(tag[i].id, tag[i].len); 101 | if (!str) { 102 | fprintf(stderr, 103 | "cannot allocate data (err=%d)\n", ret); 104 | exit(EXIT_FAILURE); 105 | } 106 | 107 | printf("%.*s %.*s %.*s %d\n", 108 | tag[i].len * 2, str, 109 | CAENRFID_SOURCE_NAME_LEN, tag[i].source, 110 | CAENRFID_READPOINT_NAME_LEN, tag[i].readpoint, 111 | tag[i].type); 112 | 113 | free(str); 114 | } 115 | 116 | /* Free inventory data */ 117 | free(tag); 118 | } 119 | 120 | caenrfid_close(&handle); 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /Chapter19/smartcard/add_TSC12xxF_reader.patch: -------------------------------------------------------------------------------- 1 | --- /etc/libccid_Info.plist.orig 2016-10-24 17:48:15.956215450 +0000 2 | +++ /etc/libccid_Info.plist 2016-10-24 17:51:50.106215475 +0000 3 | @@ -377,6 +377,7 @@ 4 | 0x08C3 5 | 0x15E1 6 | 0x062D 7 | + 0x1862 8 | 9 | 10 | ifdProductID 11 | @@ -652,6 +653,7 @@ 12 | 0x0402 13 | 0x2007 14 | 0x0001 15 | + 0x0001 16 | 17 | 18 | ifdFriendlyName 19 | @@ -927,6 +929,7 @@ 20 | Precise Biometrics Precise 200 MC 21 | RSA RSA SecurID (R) Authenticator 22 | THRC Smart Card Reader 23 | + TSC12xxF Reader 24 | 25 | 26 | Copyright 27 | -------------------------------------------------------------------------------- /Chapter19/smartcard/smart_card.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal 4 | import daemon 5 | import sys 6 | import logging 7 | from time import sleep 8 | from smartcard.CardMonitoring import CardMonitor, CardObserver 9 | from smartcard.util import * 10 | 11 | logging.basicConfig(level = logging.INFO) 12 | 13 | # 14 | # Signals handler 15 | # 16 | 17 | def sig_handler(sig, frame): 18 | sys.exit(0) 19 | 20 | # 21 | # Smart Card Observer 22 | # 23 | 24 | class printobserver(CardObserver): 25 | def update(self, observable, (addedcards, removedcards)): 26 | for card in addedcards: 27 | logging.info("->] " + toHexString(card.atr)) 28 | for card in removedcards: 29 | logging.info("<-] " + toHexString(card.atr)) 30 | 31 | # 32 | # The daemon body 33 | # 34 | 35 | def daemon_body(): 36 | # The main loop 37 | logging.info("INFO waiting for card... (hit CTRL+C to stop)") 38 | 39 | try: 40 | cardmonitor = CardMonitor() 41 | cardobserver = printobserver() 42 | cardmonitor.addObserver(cardobserver) 43 | 44 | while True: 45 | sleep(1000000) # sleep forever 46 | 47 | except: 48 | cardmonitor.deleteObserver(cardobserver) 49 | 50 | # 51 | # Main 52 | # 53 | 54 | # Define the daemon context and install the signals traps 55 | context = daemon.DaemonContext( 56 | detach_process = False, 57 | stdout = sys.stdout, 58 | stderr = sys.stderr, 59 | ) 60 | context.signal_map = { 61 | signal.SIGTERM: sig_handler, 62 | signal.SIGINT: sig_handler, 63 | } 64 | 65 | # Start the daemon 66 | with context: 67 | daemon_body() 68 | 69 | sys.exit(0) 70 | -------------------------------------------------------------------------------- /Chapter19/zwave/open-zwave-control-panel.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter19/zwave/open-zwave-control-panel.tgz -------------------------------------------------------------------------------- /Chapter19/zwave/open-zwave.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/GNU-Linux-Rapid-Embedded-Programming/09c16ec2c52591a5de9e3d4092fd25f5a5e73cea/Chapter19/zwave/open-zwave.tgz -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # GNU/Linux Rapid Embedded Programming 5 | This is the code repository for [GNU/Linux Rapid Embedded Programming](https://www.packtpub.com/hardware-and-creative/gnulinux-rapid-embedded-programming?utm_source=github&utm_medium=repository&utm_content=9781786461803), published by Packt. It contains all the supporting project files necessary to work through the book from start to finish. 6 | 7 | ## About the Book 8 | This book presents popular and user-friendly boards in the industry – such as Beaglebone Black, Atmel Xplained, Wandboard, and system-on-chip manufacturers – and lets you explore corresponding projects that make use of these boards. You will first program the embedded platforms using the C, Bash, and Python/PHP languages in order to get access to the external peripherals. You will gain a strong foundation in using embedded systems by learning how to program the device driver and access the peripherals. You will also learn how to read and write data from/to the external environment by using C programs or a scripting language (such as Bash/PHP/Python) and see how to configure a device driver for specific hardware. 9 | 10 | The final chapter shows you how to use a micro-controller board – based on the most used microcontroller – to implement real-time or specific tasks that are normally not carried out on the GNU/Linux system. After finishing this book, you will be capable of applying these skills to your personal and professional projects. 11 | 12 | ## Instructions and Navigations 13 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter01 14 | 15 | The code will look like the following: 16 | 17 | static int ngpios; 18 | static int gpios[2] = { -1 , -1 }; 19 | module_param_array(gpios, int, &ngpios, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 20 | MODULE_PARM_DESC(gpios, "Defines the GPIOs number to be used as a list of" 21 | " numbers separated by commas."); 22 | 23 | /* Logging stuff */ 24 | #define __message(level, fmt, args...) \ 25 | printk(level "%s: " fmt "\n" , NAME , ## args) 26 | 27 | There are no code files for the following chapters: 28 | 29 | - **Chapter 01** - Managing the System Console 30 | - **Chapter 18** - Pulse-Width Modulation – PWM 31 | 32 | ### Software requirements: 33 | 34 | Regarding the software you should have a little knowledge of a non graphical text editor as 35 | vi, emacs or nano. Even if you can connect an LCD display, a keyboard and a mouse 36 | directly to embedded kits and then use the graphical interface, in this book we assume that 37 | you is able to do little modifications to text files by using a text only editor. 38 | The host computer, that is the computer you will use to cross-compile the code and/or to 39 | manage your embedded systems, is assumed running a GNU/Linux based distribution. My 40 | host PC is running an Ubuntu 15.10 but you can use also a newer Ubuntu Long Term 41 | Support (LTS) or a Debian based system too with little modifications or you may use 42 | another GNU/Linux distribution but with a little effort from you mainly regarding the 43 | cross-compiling tools installation, libraries dependencies and packages management. 44 | Foreign systems such as Windows, MacOS or similar are not covered by this book due the 45 | fact you should not use low technology systems to develop code for high technology 46 | system! 47 | Knowing how a C compiler works and how to manage a Makefile is required. 48 | This book will present some kernel programming techniques but these must cannot be 49 | taken as a kernel programming course. You need a proper book for such topic! However each 50 | example is well documented and you will find several suggested resources. Regarding the 51 | kernel I'd like to state that the version used into this book is 4.4.x. 52 | As a final note I suppose that you known how to connect a GNU/Linux based board on the 53 | Internet in order to download a package or a generic file. 54 | 55 | ### Hardware requirements: 56 | 57 | In this book all code is developed for BeagleBone Black board revision C, for SAMA5D3 58 | Xplained revision A or for the WandBoard revision C1 (depending on the board used) but 59 | you can use an older revision without any issues, in fact the code is portable and it should 60 | work on other systems too (but the DTS files whose must be considered apart)! 61 | Regarding the computer peripherals used in this book I reported in each chapter where I 62 | got the hardware and where you can buy it but, of course, you can decide to surf the 63 | Internet in order to find a better and cheaper offer. A note where to find the datasheet is 64 | also present. 65 | You should not have any difficulties in order to connect the hardware presented in this 66 | book with the embedded kits since the connections are very simple and well documented. 67 | They don't require any particular hardware skills to be performed from you (apart knowing 68 | how to use a solder), however having a minor knowledge in electronics may help. 69 | 70 | 71 | ## Related Products: 72 | 73 | * [Using Yocto Project with BeagleBone Black]( https://www.packtpub.com/hardware-and-creative/yocto-beaglebone?utm_source=github&utm_medium=repository&utm_content=9781785289736 ) 74 | 75 | * [ARM® Cortex® M4 Cookbook]( https://www.packtpub.com/hardware-and-creative/arm-cortex-m4-cookbook?utm_source=github&utm_medium=repository&utm_content=9781782176503 ) 76 | 77 | * [BeagleBone Home Automation Blueprints]( https://www.packtpub.com/hardware-and-creative/beaglebone-home-automation-blueprints?utm_source=github&utm_medium=repository&utm_content=9781783986026 ) 78 | 79 | * [Building Networks and Servers Using BeagleBone]( https://www.packtpub.com/hardware-and-creative/building-networks-and-servers-using-beaglebone?utm_source=github&utm_medium=repository&utm_content=9781784390204 ) 80 | 81 | ### Suggestions and Feedback 82 | [Click here]( https://docs.google.com/forms/d/e/1FAIpQLSe5qwunkGf6PUvzPirPDtuy1Du5Rlzew23UBp2S-P3wB-GcwQ/viewform ) if you have any feedback or suggestions. 83 | 84 | 85 | ### Download a free PDF 86 | 87 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
88 |

https://packt.link/free-ebook/9781786461803

--------------------------------------------------------------------------------