File: is_key_down.c

package info (click to toggle)
quisk 4.2.32-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,064 kB
  • sloc: python: 22,219; ansic: 19,027; makefile: 38; sh: 2
file content (241 lines) | stat: -rwxr-xr-x 6,393 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include <Python.h>	// used by quisk.h
#include <complex.h>	// Used by quisk.h
#include "quisk.h"

// This module provides methods to access the state of the key.
// First call quisk_open_key(name) to choose a method and initialize.
// Subsequent key access uses the method chosen.

static int startup_error = -1;		// -1: port not opened; 0: no error opening port; 1: error opening port
static int bit_cts, bit_dsr;		// modem bits
static char use_cts, use_dsr;		// use of CTS and DSR bits
static int reverse_cts, reverse_dsr;	// opposite polarity for cts/dsr
static char port_name[QUISK_SC_SIZE];	// serial port name
static PyObject * start_up(void);	// open the serial port
static void shut_down(void);		// close the serial port
static void modem_status(void);		// test modem bits
#define MSG_SIZE	(50 + QUISK_SC_SIZE)

//int quisk_serial_key_errors = 0;
int quisk_serial_key_down;		// The cts or dsr bit for CW key is asserted
int quisk_use_serial_port;		// either cts or dsr is being used
int quisk_serial_ptt;			// The cts or dsr bit for PTT is asserted

PyObject * quisk_open_key(PyObject * self, PyObject * args, PyObject * keywds)
{  // return a message for error, or "" for no error
	static char * kwlist[] = {"port", "cts", "dsr", NULL} ;
	PyObject * msg = NULL;
	char * port = NULL;
	char * cts = NULL;
	char * dsr = NULL;

	quisk_serial_key_down = 0;
	quisk_serial_ptt = 0;
	if (!PyArg_ParseTupleAndKeywords (args, keywds, "|sss", kwlist, &port, &cts, &dsr))
		return NULL;
	//quisk_serial_cts and dsr are "None", "CW", "PTT"; and "when high" or "when low"
	if (cts) {
		use_cts = * cts;		// 'N', 'C', 'P'
		reverse_cts = strstr(cts, "when low") != NULL;
	}
	if (dsr) {
		use_dsr = * dsr;		// 'N', 'C', 'P'
		reverse_dsr = strstr(dsr, "when low") != NULL;
	}
	if (port) {
		if (startup_error == 0)		// port is open
			shut_down();
		strncpy(port_name, port, QUISK_SC_SIZE - 1);
		port_name[QUISK_SC_SIZE - 1] = 0;
		if (port_name[0])
			msg = start_up();
	}
	if (startup_error == 0 && (use_cts != 'N' || use_dsr != 'N'))
		quisk_use_serial_port = 1;
	else
		quisk_use_serial_port = 0;
	if (msg == NULL)
		msg = PyUnicode_FromString("");
	return msg;
}

PyObject * quisk_close_key(PyObject * self, PyObject * args)
{
	if (!PyArg_ParseTuple (args, ""))
		return NULL;
	shut_down();
	Py_INCREF (Py_None);
	return Py_None;
}

void quisk_poll_hardware_key(void)
{  // call frequently to check the modem bits
	if ( ! quisk_use_serial_port)
		return;
	modem_status();
	if (use_cts == 'C')
		quisk_serial_key_down = reverse_cts ? bit_cts == 0 : bit_cts != 0;
	else if (use_cts == 'P')
		quisk_serial_ptt = reverse_cts ? bit_cts == 0 : bit_cts != 0;
	if (use_dsr == 'C')
		quisk_serial_key_down = reverse_dsr ? bit_dsr == 0 : bit_dsr != 0;
	else if (use_dsr == 'P')
		quisk_serial_ptt = reverse_dsr ? bit_dsr == 0 : bit_dsr != 0;
}

#if defined(MS_WINDOWS)
#include <stdlib.h>
#include <sys/types.h>
#include <windows.h>
//#include <processthreadsapi.h>
//#include <timeapi.h>
#include <avrt.h>

static HANDLE hComm = INVALID_HANDLE_VALUE;		// Windows handle to read the serial port

static void modem_status(void)
{
	DWORD dwModemStatus;

	if (hComm == INVALID_HANDLE_VALUE) {
		bit_cts = bit_dsr = 0;
	}
	else {
		if (!GetCommModemStatus(hComm, &dwModemStatus)) {
			bit_cts = bit_dsr = 0;	// Error in GetCommModemStatus;
		}
		else {
			bit_cts = MS_CTS_ON & dwModemStatus;
			bit_dsr = MS_DSR_ON & dwModemStatus;
		}
	}
}

static PyObject * start_up(void)
{
	char msg[MSG_SIZE];

	hComm = CreateFile(port_name,  GENERIC_READ, 0, 0, OPEN_EXISTING,
		0, 0);
		//FILE_FLAG_OVERLAPPED, 0);
	if (hComm == INVALID_HANDLE_VALUE) {
		snprintf(msg, MSG_SIZE, "Open Morse key serial port %s failed.", port_name);
		startup_error = 1;
		return PyUnicode_FromString(msg);
	}
	startup_error = 0;
	return PyUnicode_FromString("");
}

static void shut_down(void)
{
	if (hComm != INVALID_HANDLE_VALUE)
        	CloseHandle(hComm);
	hComm = INVALID_HANDLE_VALUE;
	startup_error = -1;
	quisk_serial_key_down = 0;
	quisk_use_serial_port = 0;
	quisk_serial_ptt = 0;
}

// Changes for MacOS support thanks to Mario, DL3LSM.
// Broken by N2ADR April, 2020.
#elif defined(__MACH__)

static PyObject * start_up(void)
{
	startup_error = 0;
	return PyUnicode_FromString("");
}

static void shut_down(void)
{
	startup_error = -1;
	quisk_serial_key_down = 0;
	quisk_use_serial_port = 0;
	quisk_serial_ptt = 0;
}

static void modem_status(void)
{
}

#else
// Not MS Windows and not __MACH__:

// Access the serial port.  This code sets DTR high, and monitors DSR and CTS.
// When DSR is high set the RTS signal high. When DSR goes low set RTS low after a delay.

#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>

static int fdComm = -1;			// File descriptor to read the serial port

static void modem_status(void)
{
	int bits;
	struct timeval tv;
	double time;
	static double time0=0;	// time when the key was last down

        if (fdComm >= 0) {
	        ioctl(fdComm, TIOCMGET, &bits);	// read modem bits
	        bit_cts = bits & TIOCM_CTS;
	        bit_dsr = bits & TIOCM_DSR;
		if (bit_dsr) {
			if ( ! (bits & TIOCM_RTS)) {	// set RTS
				bits |= TIOCM_RTS;
				ioctl(fdComm, TIOCMSET, &bits);
			}
			gettimeofday(&tv, NULL);
			time0 = tv.tv_sec + tv.tv_usec / 1.0E6;		// time is in seconds
		}
		else if (bits & TIOCM_RTS) {	// clear RTS after a delay
			gettimeofday(&tv, NULL);
			time = tv.tv_sec + tv.tv_usec / 1.0E6;
			if (time - time0 > pt_quisk_sound_state->quiskKeyupDelay * 1E-3) {
				bits &= ~TIOCM_RTS;
				ioctl(fdComm, TIOCMSET, &bits);
			}
		}
        }
}

static PyObject * start_up(void)
{
	int bits;
	char msg[MSG_SIZE];
	struct timespec tspec;

	fdComm = open(port_name, O_RDWR | O_NOCTTY);
	if (fdComm < 0) {
		snprintf(msg, MSG_SIZE, "Open morse key serial port %s failed.", port_name);
		startup_error = 1;
		return PyUnicode_FromString(msg);
	}
	else {
		ioctl(fdComm, TIOCMGET, &bits);		// read modem bits
		bits |= TIOCM_DTR;			// Set DTR
		bits &= ~TIOCM_RTS;			// Clear RTS at first
		ioctl(fdComm, TIOCMSET, &bits);
	}
	tspec.tv_sec = 0;
	tspec.tv_nsec = 10000 * 1000;
	nanosleep(&tspec, NULL);
	startup_error = 0;
	return PyUnicode_FromString("");
}

static void shut_down(void)
{
	if (fdComm >= 0)
		close(fdComm);
	fdComm = -1;
	startup_error = -1;
	quisk_serial_key_down = 0;
	quisk_use_serial_port = 0;
	quisk_serial_ptt = 0;
}
#endif