From 4f5037080b9a0d842d81846b782ef3bf622f6d56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E9=92=A7=E5=87=AF?= <2q1w2007@163.com>
Date: Wed, 8 Jan 2025 20:16:18 +0800
Subject: [PATCH] Change GPIOD usage case from ctxless to request mode

---
 src/audio.h |  8 +++++
 src/ptt.c   | 90 +++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 71 insertions(+), 27 deletions(-)

diff --git a/src/audio.h b/src/audio.h
index f69fc1d..dfbcd8a 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -16,6 +16,10 @@
 #include <hamlib/rig.h>
 #endif
 
+#ifdef USE_GPIOD
+#include <gpiod.h>
+#endif 
+
 #include "direwolf.h"		/* for MAX_RADIO_CHANS and MAX_TOTAL_CHANS used throughout the application. */
 #include "ax25_pad.h"		/* for AX25_MAX_ADDR_LEN */
 #include "version.h"
@@ -338,6 +342,10 @@ struct audio_s {
 					/* If zero, hamlib will come up with a default for pariticular rig. */
 #endif
 
+#if defined(USE_GPIOD)
+			struct gpiod_line *gpiod_line_handle;
+#endif
+
 	    } octrl[NUM_OCTYPES];
 
 
diff --git a/src/ptt.c b/src/ptt.c
index ec09387..b1f88c1 100644
--- a/src/ptt.c
+++ b/src/ptt.c
@@ -653,28 +653,27 @@ void export_gpio(int ch, int ot, int invert, int direction)
 }
 
 #if defined(USE_GPIOD)
-int gpiod_probe(const char *chip_name, int line_number)
-{
-	struct gpiod_chip *chip;
-	chip = gpiod_chip_open_by_name(chip_name);
-	if (chip == NULL) {
-		text_color_set(DW_COLOR_ERROR);
-		dw_printf ("Can't open GPIOD chip %s.\n", chip_name);
-		return -1;
-	}
 
-	struct gpiod_line *line;
-	line = gpiod_chip_get_line(chip, line_number);
-	if (line == NULL) {
+int gpiod_set(struct gpiod_line* line, int ptt){
+	int rc=0;
+	bool owner = gpiod_line_is_requested(line);
+	if(owner){
+		int rc2 = gpiod_line_set_value(line, ptt);
+		if (rc2 !=0) {
+			text_color_set(DW_COLOR_ERROR);
+			dw_printf ("Error: gpiod_line_set_value %s %d, errno=%d\n", gpiod_chip_name(gpiod_line_get_chip(line)), gpiod_line_offset(line),errno);
+			rc=rc-2;
+		}
+	}else{
 		text_color_set(DW_COLOR_ERROR);
-		dw_printf ("Can't get GPIOD line %d.\n", line_number);
-		return -1;
+		dw_printf ("Error: didnot request %s %d,\n", gpiod_chip_name(gpiod_line_get_chip(line)), gpiod_line_offset(line));
+		rc=rc-1;
 	}
-	if (ptt_debug_level >= 2) {
-		text_color_set(DW_COLOR_DEBUG);
-		dw_printf("GPIOD probe OK. Chip: %s line: %d\n", chip_name, line_number);
-	}
-	return 0;
+	if (ptt_debug_level >= 1) {
+			text_color_set(DW_COLOR_DEBUG);
+			dw_printf("PTT_METHOD_GPIOD chip: %s line: %d ptt: %d  rc: %d\n", gpiod_chip_name(gpiod_line_get_chip(line)), gpiod_line_offset(line), ptt, rc);
+		}
+	return rc;
 }
 #endif   /* USE_GPIOD */
 #endif   /* not __WIN32__ */
@@ -933,7 +932,34 @@ void ptt_init (struct audio_s *audio_config_p)
 	      if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
 	        const char *chip_name = audio_config_p->achan[ch].octrl[ot].out_gpio_name;
 	        int line_number = audio_config_p->achan[ch].octrl[ot].out_gpio_num;
-	        int rc = gpiod_probe(chip_name, line_number);
+	        int rc=0;
+			struct gpiod_chip *chip;
+			chip = gpiod_chip_open_by_name(chip_name);
+			if (chip == NULL) {
+				text_color_set(DW_COLOR_ERROR);
+				dw_printf ("Can't open GPIOD chip %s.\n", chip_name);
+				rc=rc-1;
+			}
+			struct gpiod_line *line;
+			line = gpiod_chip_get_line(chip, line_number);
+			if (line == NULL) {
+				text_color_set(DW_COLOR_ERROR);
+				dw_printf ("Can't get GPIOD line %d.\n", line_number);
+				rc=rc-2;
+			}else{
+				audio_config_p->achan[ch].octrl[ot].gpiod_line_handle=line;
+			}
+			if ( gpiod_line_request_output(line, "direwolf", 0) != 0 ) {
+				text_color_set(DW_COLOR_ERROR);
+				dw_printf ("Can't request GPIOD line %d.\n", line_number);
+				rc=rc-4;
+			}else{
+				dw_printf ("Request GPIOD line %d.\n", line_number);
+			}
+			if (ptt_debug_level >= 2) {
+				text_color_set(DW_COLOR_DEBUG);
+				dw_printf("GPIOD probe OK. Chip: %s line: %d\n", chip_name, line_number);
+			}
 	        if (rc < 0) {
 	          text_color_set(DW_COLOR_ERROR);
 	          dw_printf ("Disable PTT for channel %d\n", ch);
@@ -1387,13 +1413,9 @@ void ptt_set (int ot, int chan, int ptt_signal)
 
 #if defined(USE_GPIOD)
 	if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
-		const char *chip = save_audio_config_p->achan[chan].octrl[ot].out_gpio_name;
-		int line = save_audio_config_p->achan[chan].octrl[ot].out_gpio_num;
-		int rc = gpiod_ctxless_set_value(chip, line, ptt, false, "direwolf", NULL, NULL);
-		if (ptt_debug_level >= 1) {
-			text_color_set(DW_COLOR_DEBUG);
-			dw_printf("PTT_METHOD_GPIOD chip: %s line: %d ptt: %d  rc: %d\n", chip, line, ptt, rc);
-		}
+		struct gpiod_line *line = save_audio_config_p->achan[chan].octrl[ot].gpiod_line_handle;
+		gpiod_set(line, ptt);
+		
 	}
 #endif /* USE_GPIOD */
 #endif
@@ -1600,6 +1622,20 @@ void ptt_term (void)
 	  }
 	}
 #endif
+#if defined(USE_GPIOD)
+    // GPIOD
+	for (int ch = 0; ch < MAX_RADIO_CHANS; ch++) {
+	  if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
+	    for (int ot = 0; ot < NUM_OCTYPES; ot++) {
+	      if (save_audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) {
+	        struct gpiod_line *line = save_audio_config_p->achan[ch].octrl[ot].gpiod_line_handle;
+	        gpiod_line_release(line);
+			save_audio_config_p->achan[ch].octrl[ot].gpiod_line_handle=NULL;
+	      }
+	    }
+	  }
+	}
+#endif /* USE_GPIOD */
 }