How to set XDG_RUNTIM_DIR environmental variable? - raspberry-pi

I'm working on a Raspberry Pi 4 with Raspbian OS. When I try to execute a python script, I obtain the error:
XDG_RUNTIME_DIR not set in the environment. How can I fix this issue? I'm working with an ArduCAM multicamera module (https://github.com/ArduCAM/RaspberryPi/blob/master/Multi_Camera_Adapter/Multi_Adapter_Board_4Channel/Multi_Camera_Adapter_V2.2_python/) and this is the script (called by init_camera.sh):
import RPi.GPIO as gp
import os
gp.setwarnings(False)
gp.setmode(gp.BOARD)
gp.setup(7, gp.OUT)
gp.setup(11, gp.OUT)
gp.setup(12, gp.OUT)
def main():
print('Start testing the camera A')
i2c = "i2cset -y 1 0x70 0x00 0x04"
os.system(i2c)
gp.output(7, False)
gp.output(11, False)
gp.output(12, True)
capture(1)
print('Start testing the camera B')
i2c = "i2cset -y 1 0x70 0x00 0x05"
os.system(i2c)
gp.output(7, True)
gp.output(11, False)
gp.output(12, True)
capture(2)
print('Start testing the camera C')
i2c = "i2cset -y 1 0x70 0x00 0x06"
os.system(i2c)
gp.output(7, False)
gp.output(11, True)
gp.output(12, False)
capture(3)
print('Start testing the camera D')
i2c = "i2cset -y 1 0x70 0x00 0x07"
os.system(i2c)
gp.output(7, True)
gp.output(11, True)
gp.output(12, False)
capture(4)
def capture(cam):
cmd = "libcamera-still -o capture_%d.jpg" % cam
os.system(cmd)
if __name__ == "__main__":
main()
gp.output(7, False)
gp.output(11, False)
gp.output(12, True)

Related

I cannot access STM32 DMA register when configuring it

I currently use standard peripheral library to write a driver that enable memory to USART6_TX DMA transfer on a STM32 F407 ZGT6 chip. However, I tried for a long time but the initialization keeps on failing: DMA_GetCmdStatus always returns DISABLE. By using GDB, I found that after the DMA_Init try to write configuration into DMA register, DMA CR register remains 0. The DMA initialize code and execution are as follow:
void DMA_USART6_Init(char* DMA_Start_Pos, uint32_t DMA_Buffer_Size){
DMA_Buffer_Size_GV = DMA_Buffer_Size;
DMA_Start_Pos_GV = DMA_Start_Pos;
/*RCC config*/
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
/*DMA init*/
//DMA_DeInit(DMA2_Stream7);
DMA_Cmd(DMA2_Stream7, DISABLE);
while ((DMA_GetCmdStatus(DMA2_Stream7) == ENABLE)){}
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_Channel = DMA_Channel_5;
DMA_InitStruct.DMA_PeripheralBaseAddr = USART6_BASE + 0x04;//(uint32_t)&USART6->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t) dubuff;//(uint32_t) DMA_Start_Pos;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = (uint16_t)sizeof(dubuff);//DMA_Buffer_Size;
printf("buffer size should be %d \r\n", (uint16_t)sizeof(dubuff));
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_Init(DMA2_Stream7, &DMA_InitStruct);
printf("data counter after init %d \r\n", DMA_GetCurrDataCounter(DMA2_Stream7));
}
for the ENABLE code
void DMA_USART6_Enable_DMA(char* DMA_Start_Pos, uint32_t DMA_Buffer_Size, int MB){
Max_Buffer = MB;
USART6_init_for_DMA();
DMA_USART6_Init(DMA_Start_Pos, DMA_Buffer_Size);
DMA_USART6_NVIC_Init();
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream7, ENABLE);
while ((DMA_GetCmdStatus(DMA2_Stream7) == DISABLE)){}//program stucked in this loop
}
for the USART6 code:
void USART6_init_for_DMA(void){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 57600;//115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART6, &USART_InitStructure);
USART_Cmd(USART6, ENABLE);
USART_DMACmd(USART6, USART_DMAReq_Tx, ENABLE);
}
and the GDB result:
the value that should be written into DMA CR register
text in the picture 1:
367 DMAy_Streamx->CR = tmpreg;
(gdb) print tmpreg
$7 = 167904576
the DMA CR register remains 0
text in the picture2:
371 tmpreg = DMAy_Streamx->FCR;
(gdb) print *DMAy_Streamx
$10 = {CR = 0, NDTR = 0, PAR = 0, M0AR = 0, M1AR = 0, FCR = 0}
Please tell me if there is anything I can provide about my problem or things I can try further...
Note: In the same program, my USART6 and GPIO works fine.
When the desired stream is activated, the relevant registers can no longer be configured. Only in dual buffer mode can memory addresses 0 and 1 be updated according to the bit CT function. You must first deactivate the relevant channel and then apply the changes.
I am OP.
At the start, I have a feeling that it could be an obvious mistake and that's true.
It turns out that I should use RCC_AHB1PeriphClockCmd instead of RCC_AHB1PeriphResetCmd because OBVIOUSLY the later accessed RSTR (RCC Reset register) rather than ENR an thus clock is not enable (about that Codo is right).
Well, Hope guys whoever sees this question won't repeat this embarrass mistake ;(

Issue using UART with STM32F0Discovery and Fingerprint Scanner

I am currently working on a project that involves the STM32f0Discovery board and this fingerprint scanner, which uses UART communication. To initialize the UART, I do the following:
void init_uart(void){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
Then to send/receive a byte I do the following:
void writechar(char c) {
while((USART1 -> ISR & USART_ISR_TC) != USART_ISR_TC);
USART1 -> TDR = c;
}
char readchar(void) {
return USART_ReceiveData(USART1);
}
To test this, I sent the OPEN command byte-by-byte through a for-loop, then the LEN-ON command the same method, which has no results. When reading for an ACK after the OPEN command, the results read are just an empty array of char bytes.
So, my question is, is my initialization the error? Or is the error in the reading/writing? Or could it be something else altogether?
Are you getting the ACK response ? If you are not then there is probably a configuration or wiring problem. I would suggest you try connecting the serial pins to a serial-usb converter
(FTDI such as this :Click here)
and use an app like Putty or YAT to send commands (ACK) to and from your stm. Try using the same configuration the scanner has if that doesn't work its a problem with your config if it does work its a problem scanner side.

STM32F4-Discovery SPI LIS3DSH

I was able to use the code below to init the SPI and read the values from accelerometer
SPI_InitTypeDef SPI_InitTypeDefStruct;
GPIO_InitTypeDef GPIO_InitTypeDefStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE , ENABLE);
SPI_InitTypeDefStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitTypeDefStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitTypeDefStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitTypeDefStruct.SPI_CPOL = SPI_CPOL_High;
SPI_InitTypeDefStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitTypeDefStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
SPI_InitTypeDefStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //seems like it was here causing trouble
SPI_InitTypeDefStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitTypeDefStruct);
GPIO_InitTypeDefStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_6;
GPIO_InitTypeDefStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitTypeDefStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitTypeDefStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitTypeDefStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitTypeDefStruct);
GPIO_InitTypeDefStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitTypeDefStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitTypeDefStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitTypeDefStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitTypeDefStruct.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOE, &GPIO_InitTypeDefStruct);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
GPIO_SetBits(GPIOE, GPIO_Pin_3);
SPI_Cmd(SPI1, ENABLE);
SPI_send(0x23, 0xc9); // resetting the accelerometer internal circuit
//SPI_send(0x20, 0x67); // 100Hz data update rate, block data update disable, x/y/z enabled
SPI_send(0x20, 0x97);
//SPI_send(0x24, 0x20); // Anti aliasing filter bandwidth 800Hz, 16G (very sensitive), no self-test, 4-wire interface
SPI_send(0x24, 0x00); // Anti aliasing filter bandwidth 800Hz, 2G ( sensitive ??), no self-test, 4-wire interface
SPI_send(0x10, 0x00); // Output(X) = Measurement(X) - OFFSET(X) * 32;
SPI_send(0x11, 0x00); // Output(Y) = Measurement(Y) - OFFSET(Y) * 32;
SPI_send(0x12, 0x00); // Output(Z) = Measurement(Z) - OFFSET(Z) * 32;
void SPI_send(uint8_t address, uint8_t data)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_3);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, address);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
SPI_I2S_ReceiveData(SPI1);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, data);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
SPI_I2S_ReceiveData(SPI1);
GPIO_SetBits(GPIOE, GPIO_Pin_3);
}
uint8_t SPI_read(uint8_t address)
{
GPIO_ResetBits(GPIOE, GPIO_Pin_3);
address = 0x80 | address; // 0b10 - reading and clearing status
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, address);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
SPI_I2S_ReceiveData(SPI1);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI1, 0x00);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
GPIO_SetBits(GPIOE, GPIO_Pin_3);
return SPI_I2S_ReceiveData(SPI1);
}
Then I combined these code with my project which has an 500Hz interrupt.
It always work at first but if i unplug the board then plug it in again, SPI will only read zeros, even though the LIS3DSH still have readings(i used oscilloscope checked it). I had to download the shorter version of the project code( taking out most of the code in the interrupt) to get SPI to work properly again.
I am using the Kickstart, size-limited IAR ewarm I thought it was because my code exceed the limit. But I did not get warning and my code was not more than 32kb.
I am just confused since it works until I unplug it. Could someone give me some suggestions?
Thanks
I decided just to add the SPI_DeInit(...) before SPI_Init(...). This seems to solve the problem. I still dont understand why it wont reset itself though.

STM32 how to set a slave I2C port

I have an issue with STM32F0 Discovery.
I am using I2C1 (like master) to send start condition and address to I2C2 (slave) on the same board.
I am able to generate propertly the signal but the IC2 (slave) is not able to generate an ACK on 9th clk
What's wrong?
Here my code about the setup:
void set_I2C(void){
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
/* Configure the I2C clock source. The clock is derived from the HSI */
RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_1);
//Configure pins: SCL and SDA ------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_Cmd(I2C1, DISABLE);
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 0x00;
I2C_InitStructure.I2C_OwnAddress1 = 0x40;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Timing =0xB0420F13; //100KHz
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
//Set up of I2C2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
//Configure pins: SCL and SDA ------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C2);
I2C_Cmd(I2C2, DISABLE);
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Disable;
I2C_InitStructure.I2C_DigitalFilter = 0x00;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Timing =0xB0420F13;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &I2C_InitStructure);
I2C_Cmd(I2C2, ENABLE);
I2C_ITConfig(I2C2, I2C_AcknowledgedAddress_7bit, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the I2C2 interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = I2C2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
I had the same problem. It was caused by absence of the required for I2C external pull-up resistors. You can't just use an internal MCU's pull-ups. You MUST use external ones.
Detailed explanation is provided in these articles:
http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
https://electronics.stackexchange.com/questions/1849/is-there-a-correct-resistance-value-for-pull-up-resistors
I run into similar issue.
In my case the solution was to add a HAL_I2C_EnableListen_IT() after initialization to activate I2C slave (I am using HAL libraries, but you can check what the above function does in details).

Pull GPIO pin low as last act prior to shutting down

I want to signal a power off state by pulling a GPIO pin low for 10 seconds. I have discovered the run levels in the /etc/rc.* directories. Eventually the "halt" command gets run.
I'd like to edit and recompile the halt.c file, but I am unable to locate it. I have two questions:
Is this the right approach?
Where is the source code? (pending positive answer from Q1).
Thank you.
Justin
I haven't used the Raspberry Pi, but on most systems halt, poweroff and reboot are all links to the same binary. Another way to do this would be to just write a program to do what you want and make it the last thing to be called in /etc/rc.d/rc0.d. Runlevel 0 is what the system does when it shuts down.
Here is my take on this problem 'powerctl_pin'
https://pastebin.com/BdzGM5TJ
/*
Raspi3B Power Control Pin Raspbian Jessie
Bilgus -- 2017 CC-BY-SA 3.0
Requires WiringPI http://wiringpi.com/
Compiling:
gcc -o powerctl_pin powerctl_pin.c -l wiringPi && chmod +x powerctl_pin &&
sudo cp powerctl_pin /bin/
Install:
sudo /bin/powerctl_pin 21 install
Uninstall:
sudo /bin/powerctl_pin 21 uninstall
Shutdown:
sudo /bin/powerctl_pin 21 poweroff
/bin/powerctl_pin Broadcom_pin#, mode
Valid Modes: poweroff, poweron, install, uninstall
Works with mosfet latch switch
https://easyeda.com/Bilgus/New_Project-4ce1316bb1f6402985f8d1c4f196448d
Original Circuit:
http://www.mosaic-industries.com/embedded-systems/microcontroller-projects
/raspberry-pi/on-off-power-controller
*/
/*
Raspi3B Power Control Pin Raspbian Jessie
Bilgus -- 2017 CC-BY-SA 3.0
Requires WiringPI http://wiringpi.com/
Compiling:
gcc -o powerctl_pin powerctl_pin.c -l wiringPi && chmod +x powerctl_pin &&
sudo cp powerctl_pin /bin/
Install:
sudo /bin/powerctl_pin 21 install
Uninstall:
sudo /bin/powerctl_pin 21 uninstall
Shutdown:
sudo /bin/powerctl_pin 21 poweroff
/bin/powerctl_pin Broadcom_pin#, mode
Valid Modes: poweroff, poweron, install, uninstall
Works with mosfet latch switch
https://easyeda.com/Bilgus/New_Project-4ce1316bb1f6402985f8d1c4f196448d
Original Circuit:
http://www.mosaic-industries.com/embedded-systems/microcontroller-projects
/raspberry-pi/on-off-power-controller
*/
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <signal.h> //sigterm, sigint()
#include "wiringPi.h"
#define WIRINGPI_CODES 999 /* enable error checking on setup */
#define POWEROFF_SVC "PwrCtl_Pin.service"
#define POWEROFF_SVC_PATH "/lib/systemd/system/"POWEROFF_SVC
#define REQUIRES "shutdown.target umount.target final.target poweroff.target"
#define AFTER "shutdown.target umount.target final.target"
#define BEFORE "systemd-poweroff.service"
#define WANTEDBY "poweroff.target"
#define POWERINT_SVC "PwrCtl_Pin-Interrupt.service"
#define POWERINT_SVC_PATH "/lib/systemd/system/"POWERINT_SVC
static void poweroff_ISR_INIT(int pin);
static int g_pin = 0;
/* enables pullup - unneeded to hold latch */
static void poweron_pin(int pin)
{
pullUpDnControl(pin, PUD_UP);
pinMode(pin, INPUT);
}
/* pulls pin low in short loop to turn power off */
static void poweroff_pin(int pin)
{
pullUpDnControl(pin, PUD_OFF);
int c;
for(c=0;c<20;c++)
{
//pinMode(pin, INPUT);
//pullUpDnControl(pin, PUD_DOWN);
digitalWrite(pin,LOW);
pinMode(pin, OUTPUT);
digitalWrite(pin,LOW);
delay(500);
}
}
/* ISR Called when pin goes from high to low debounce checks that still low */
static void poweroff_ISR(void)
{
delay(100);
if (digitalRead(g_pin) == LOW) /* pin debounce */
{
openlog ("Poweroff ISR", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
syslog (LOG_NOTICE, "ISR Triggered - Shutdown -h now");
closelog();
system("shutdown -h now");
exit(0);
}
else
poweroff_ISR_INIT(g_pin);
}
/* signal handler recieves shutdown signals */
static void signal_handler(int signal_0)
{
if (signal_0 == SIGINT || signal_0 == SIGTERM || signal_0 == SIGSTOP)
exit(0);
}
/* Initialize Poweroff ISR handler */
static void poweroff_ISR_INIT(int pin)
{
g_pin = pin;
pinMode(pin, INPUT);
pullUpDnControl(pin, PUD_UP);
wiringPiISR(pin, INT_EDGE_FALLING, &poweroff_ISR);
while(1)
{
delay(100);
;;
}
}
/* creates service daemons */
static void install(int pin, char *prog_path)
{
FILE *f = fopen(POWEROFF_SVC_PATH, "w");
if (f == NULL)
{
fprintf(stderr, "Error opening file! %s\n", POWEROFF_SVC_PATH);
exit(-6);
}
fprintf(f, "# POWER CONTROL PIN SERVICE \n# %s\n\n", prog_path);
fprintf(f, "[Unit]\nDescription=PowerCtl_Pin pulls GPIO pin %i LOW\n", pin);
fprintf(f, "DefaultDependencies=no\n");
fprintf(f, "Requires=%s\n", REQUIRES);
fprintf(f, "After=%s\nBefore=%s\n\n", AFTER, BEFORE);
fprintf(f, "[Service]\nType=oneshot\n");
fprintf(f, "ExecStart=%s %i poweroff\n\n", prog_path, pin);
fprintf(f, "[Install]\nWantedBy=%s\n\n", WANTEDBY);
fclose(f);
printf("Service file created: %s\n", POWEROFF_SVC_PATH);
system("systemctl enable " POWEROFF_SVC);
FILE *f1 = fopen(POWERINT_SVC_PATH, "w");
if (f1 == NULL)
{
fprintf(stderr, "Error opening file! %s\n", POWERINT_SVC_PATH);
exit(-7);
}
fprintf(f1, "# POWER CONTROL PIN INTERRUPT SERVICE \n");
fprintf(f1, "# %s\n\n", prog_path);
fprintf(f1, "[Unit]\nDescription=PowerCtl_Pin Interrupt watches GPIO ");
fprintf(f1, "for pin %i LOW calls shutdown now\n", pin);
fprintf(f1, "DefaultDependencies=no\n");
fprintf(f1, "After=network.target\n\n");
fprintf(f1, "[Service]\nType=simple\n");
fprintf(f1, "ExecStart=%s %i interrupt &\n", prog_path, pin);
fprintf(f1, "TimeoutSec=0\nRestart=always\n\n");
fprintf(f1, "[Install]\nWantedBy=multi-user.target\n\n");
fclose(f1);
printf("\n\rService file created: %s\n", POWERINT_SVC_PATH);
system("systemctl enable " POWERINT_SVC);
printf("Attempting to start: %s\n\r", POWERINT_SVC_PATH);
system("systemctl start " POWERINT_SVC);
}/*install*/
/* disables/stops service daemons */
static void uninstall(int pin, char *prog_path)
{
system("systemctl disable " POWEROFF_SVC);
printf("Service file still exists: %s\n\n", POWEROFF_SVC_PATH);
system("systemctl stop " POWERINT_SVC);
system("systemctl disable " POWERINT_SVC);
printf("Service file still exists: %s\n", POWERINT_SVC_PATH);
}
int main(int argc, char **argv)
{
int pin = 0;
if (geteuid() != 0)
{
fprintf (stderr, "You need to be root to run this program. (sudo?)\n") ;
exit(-1);
}
putenv("WIRINGPI_CODES=WhOkNoWs??");
if (wiringPiSetupGpio() != 0) /* change to wiringPiSetup() for WiringPi Pins*/
{
fprintf(stderr, "wiringPiSetup error\n");
exit(-2);
}
if(argc < 3)
{
fprintf (stderr, "not enough args poweroff_pin(brcm_pin# mode)\n") ;
fprintf (stderr, "Valid Mode [power[off/on], interrupt, install, uninstall]])\n") ;
exit(-3);
}
else if (sscanf (argv[1],"%i", &pin) != 1)
{
fprintf (stderr, "invalid pin number, poweroff_pin(brcm_pin# mode) ");
fprintf (stderr, "Valid Mode [power[off/on], interrupt, install, uninstall]])\n") ;
exit(-4);
}
else if(strncmp(argv[2],"interrupt",10) == 0)
{
openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
syslog (LOG_NOTICE, "%s - interrupt mode pin = %s", argv[0], argv[1]);
closelog();
if (signal(SIGINT, signal_handler) == SIG_ERR)
{
fprintf(stderr, "Unable to register signal handler\n");
exit(-5);
}
poweroff_ISR_INIT(pin);
}
else if(strncmp(argv[2],"poweroff",10) == 0)
{
poweroff_pin(pin);
}
else if(strncmp(argv[2],"install",10) == 0)
{
openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
syslog (LOG_NOTICE, "%s - install pin = %s", argv[0], argv[1]);
closelog();
install(pin, argv[0]);
}
else if(strncmp(argv[2],"uninstall",10) == 0)
{
openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
syslog (LOG_NOTICE, "%s - uninstall pin = %s", argv[0], argv[1]);
closelog();
uninstall(pin, argv[0]);
}
else
{
poweron_pin(pin);
}
return 0;
}/*main*/