kopia lustrzana https://github.com/Hamlib/Hamlib
rodzic
c59b5383e9
commit
bc6c14e430
1
NEWS
1
NEWS
|
@ -14,6 +14,7 @@ Version 5.x -- future
|
||||||
|
|
||||||
Version 4.6
|
Version 4.6
|
||||||
* 2023-11-XX -- Planned for Nov 2023
|
* 2023-11-XX -- Planned for Nov 2023
|
||||||
|
* Add Apex Shared Loop rotator -- unidirectional only so far
|
||||||
* Add client_version to rigctld so client can report it's version for future use/compatility/alternatives
|
* Add client_version to rigctld so client can report it's version for future use/compatility/alternatives
|
||||||
* Add --set-conf=tuner_control_pathname=hamlib_tuner_control (default)
|
* Add --set-conf=tuner_control_pathname=hamlib_tuner_control (default)
|
||||||
If file exists then it will be called with 0/1 (Off/On) argument
|
If file exists then it will be called with 0/1 (Off/On) argument
|
||||||
|
|
|
@ -50,7 +50,7 @@ dnl Beware of duplication should a backend directory include both rig and
|
||||||
dnl rotor definitions, e.g. "dummy". Optional backends will not be listed
|
dnl rotor definitions, e.g. "dummy". Optional backends will not be listed
|
||||||
dnl here but will be added later, e.g. "winradio".
|
dnl here but will be added later, e.g. "winradio".
|
||||||
RIG_BACKEND_LIST="rigs/adat rigs/alinco rigs/aor rigs/barrett rigs/codan rigs/dorji rigs/drake rigs/dummy rigs/elad rigs/flexradio rigs/icom rigs/icmarine rigs/jrc rigs/kachina rigs/kenwood rigs/kit rigs/lowe rigs/pcr rigs/prm80 rigs/racal rigs/rft rigs/rs rigs/skanti rigs/tapr rigs/tentec rigs/tuner rigs/uniden rigs/winradio rigs/wj rigs/yaesu rigs/gomspace rigs/mds"
|
RIG_BACKEND_LIST="rigs/adat rigs/alinco rigs/aor rigs/barrett rigs/codan rigs/dorji rigs/drake rigs/dummy rigs/elad rigs/flexradio rigs/icom rigs/icmarine rigs/jrc rigs/kachina rigs/kenwood rigs/kit rigs/lowe rigs/pcr rigs/prm80 rigs/racal rigs/rft rigs/rs rigs/skanti rigs/tapr rigs/tentec rigs/tuner rigs/uniden rigs/winradio rigs/wj rigs/yaesu rigs/gomspace rigs/mds"
|
||||||
ROT_BACKEND_LIST="rotators/amsat rotators/ars rotators/celestron rotators/cnctrk rotators/grbltrk rotators/easycomm rotators/ether6 rotators/flir rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron rotators/satel rotators/radant"
|
ROT_BACKEND_LIST="rotators/amsat rotators/apex rotators/ars rotators/celestron rotators/cnctrk rotators/grbltrk rotators/easycomm rotators/ether6 rotators/flir rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron rotators/satel rotators/radant"
|
||||||
# Amplifiers are all in the amplifiers directory
|
# Amplifiers are all in the amplifiers directory
|
||||||
AMP_BACKEND_LIST="amplifiers/elecraft amplifiers/gemini"
|
AMP_BACKEND_LIST="amplifiers/elecraft amplifiers/gemini"
|
||||||
|
|
||||||
|
@ -843,6 +843,7 @@ bindings/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
doc/hamlib.cfg
|
doc/hamlib.cfg
|
||||||
rotators/amsat/Makefile
|
rotators/amsat/Makefile
|
||||||
|
rotators/apex/Makefile
|
||||||
rotators/ars/Makefile
|
rotators/ars/Makefile
|
||||||
rotators/celestron/Makefile
|
rotators/celestron/Makefile
|
||||||
rotators/cnctrk/Makefile
|
rotators/cnctrk/Makefile
|
||||||
|
|
|
@ -666,6 +666,20 @@
|
||||||
//! @endcond
|
//! @endcond
|
||||||
#define ROT_MODEL_FLIR ROT_MAKE_MODEL(ROT_FLIR, 1)
|
#define ROT_MODEL_FLIR ROT_MAKE_MODEL(ROT_FLIR, 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A macro that returns the model number of the APEX backend.
|
||||||
|
*
|
||||||
|
* \def ROT_MODEL_APEX
|
||||||
|
*
|
||||||
|
* The APEX backend can be used with APEX * rotators.
|
||||||
|
*/
|
||||||
|
//! @cond Doxygen_Suppress
|
||||||
|
#define ROT_APEX 26
|
||||||
|
#define ROT_BACKEND_APEX "apex"
|
||||||
|
//! @endcond
|
||||||
|
#define ROT_MODEL_APEX_SHARED_LOOP ROT_MAKE_MODEL(ROT_APEX, 1)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Convenience type definition for a rotator model.
|
* \brief Convenience type definition for a rotator model.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := apex.c sharedloop.c
|
||||||
|
LOCAL_MODULE := apex
|
||||||
|
|
||||||
|
LOCAL_CFLAGS :=
|
||||||
|
LOCAL_C_INCLUDES := android include src
|
||||||
|
LOCAL_LDLIBS := -lhamlib -Lobj/local/$(TARGET_ARCH_ABI)
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libhamlib-apex.la
|
||||||
|
libhamlib_apex_la_SOURCES = apex.c sharedloop.c
|
||||||
|
|
||||||
|
EXTRA_DIST = Android.mk
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include <hamlib/rotator.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "iofunc.h"
|
||||||
|
#include "register.h"
|
||||||
|
#include "apex.h"
|
||||||
|
|
||||||
|
float apex_azimuth;
|
||||||
|
|
||||||
|
char apex_info[64];
|
||||||
|
|
||||||
|
static pthread_t apex_read_thread;
|
||||||
|
|
||||||
|
// We only have two strings to get
|
||||||
|
// one is 18 chars and the other may be variable
|
||||||
|
// [T4BRFA99H00M010#] Unidirectional
|
||||||
|
// <VER> xxxxxxxxxx
|
||||||
|
// So we'll read 5 chars and use the to determine how to read the rest
|
||||||
|
|
||||||
|
static int apex_get_string(ROT *rot, char *s, int maxlen)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
struct rot_state *rs = &rot->state;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
memset(s, 0, maxlen);
|
||||||
|
|
||||||
|
retval = read_string(&rs->rotport, (unsigned char *)buf,
|
||||||
|
sizeof(buf),
|
||||||
|
"\n", strlen("\n"), sizeof(buf), 1);
|
||||||
|
strncpy(s, buf, maxlen);
|
||||||
|
strtok(s, "\r\n"); // truncate any CR/LF
|
||||||
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: %d bytes '%s'\n", __func__, retval, s);
|
||||||
|
|
||||||
|
if (retval <= 0) { return -RIG_EPROTO; }
|
||||||
|
|
||||||
|
return RIG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Expecting # from 0-7
|
||||||
|
// [T4BRFA99H00M010#] Unidirectional
|
||||||
|
// Or
|
||||||
|
// [T4BRFA99H00M020#] Bidirectional
|
||||||
|
static void *apex_read(void *arg)
|
||||||
|
{
|
||||||
|
ROT *rot = arg;
|
||||||
|
int retval = 0;
|
||||||
|
char data[64];
|
||||||
|
int expected_return_length = 63;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
apex_get_string(rot, data, expected_return_length);
|
||||||
|
|
||||||
|
if (strstr(data, "<VER>"))
|
||||||
|
{
|
||||||
|
strncpy(apex_info, data, sizeof(apex_info));
|
||||||
|
rig_debug(RIG_DEBUG_TRACE, "%s: apex_info=%s\n", __func__, apex_info);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval != 0 || strstr(data, "[T4BRFA99") == NULL)
|
||||||
|
{
|
||||||
|
rig_debug(RIG_DEBUG_ERR, "%s: unknown apex status message=%s\n", __func__,
|
||||||
|
data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: data='%s'\n", __func__, data);
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
{
|
||||||
|
switch (data[16])
|
||||||
|
{
|
||||||
|
case '0': apex_azimuth = 45; break;
|
||||||
|
|
||||||
|
case '1': apex_azimuth = 90; break;
|
||||||
|
|
||||||
|
case '2': apex_azimuth = 135; break;
|
||||||
|
|
||||||
|
case '3': apex_azimuth = 180; break;
|
||||||
|
|
||||||
|
case '4': apex_azimuth = 225; break;
|
||||||
|
|
||||||
|
case '5': apex_azimuth = 270; break;
|
||||||
|
|
||||||
|
case '6': apex_azimuth = 315; break;
|
||||||
|
|
||||||
|
case '7': apex_azimuth = 0; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("az=%f\n", apex_azimuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int apex_open(ROT *rot)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
char *cmdstr = "[GETVER]\r"; // does this work on all Apex controllers?
|
||||||
|
struct rot_state *rs = &rot->state;
|
||||||
|
|
||||||
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: entered\n", __func__);
|
||||||
|
|
||||||
|
apex_azimuth = -1; // we check to see if we've seen azimuth at least one time
|
||||||
|
rig_flush(&rs->rotport);
|
||||||
|
retval = write_block(&rs->rotport, (unsigned char *) cmdstr, strlen(cmdstr));
|
||||||
|
|
||||||
|
if (retval != RIG_OK)
|
||||||
|
{
|
||||||
|
rig_debug(RIG_DEBUG_ERR, "%s: write_block failed - %s\n", __func__,
|
||||||
|
rigerror(retval));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_create(&apex_read_thread, NULL, apex_read, rot);
|
||||||
|
return RIG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *apex_get_info(ROT *rot)
|
||||||
|
{
|
||||||
|
return apex_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_INITROT_BACKEND(apex)
|
||||||
|
{
|
||||||
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||||
|
|
||||||
|
rot_register(&apex_shared_loop_rot_caps);
|
||||||
|
|
||||||
|
return RIG_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Hamlib Rotator backend - Apex rotators
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ROT_APEX_H
|
||||||
|
#define _ROT_APEX_H 1
|
||||||
|
|
||||||
|
extern const struct rot_caps apex_shared_loop_rot_caps;
|
||||||
|
|
||||||
|
extern float apex_azimuth;
|
||||||
|
|
||||||
|
extern int apex_open(ROT *rot);
|
||||||
|
extern const char *apex_get_info(ROT *rot);
|
||||||
|
|
||||||
|
#endif /* _ROT_APEX_H */
|
|
@ -0,0 +1,42 @@
|
||||||
|
[T4BRFA99H00M0107] -- 0 degrees
|
||||||
|
[T4BRFA99H00M0100] -- 45 degrees
|
||||||
|
[T4BRFA99H00M0101] -- 90 degrees
|
||||||
|
[T4BRFA99H00M0102] -- 135 degrees
|
||||||
|
[T4BRFA99H00M0103] -- 180 degrees
|
||||||
|
[T4BRFA99H00M0104] -- 225 degrees
|
||||||
|
[T4BRFA99H00M0105] -- 270 degrees
|
||||||
|
[T4BRFA99H00M0106] -- 315 degrees
|
||||||
|
|
||||||
|
These are the bidirectional answers
|
||||||
|
[T4BRFA99H00M0200] -- 45
|
||||||
|
[T4BRFA99H00M0201] -- 90
|
||||||
|
[T4BRFA99H00M0202] -- 135
|
||||||
|
[T4BRFA99H00M0203] -- 180 Bidirectional N/S
|
||||||
|
[T4BRFA99H00M0204] -- 225
|
||||||
|
[T4BRFA99H00M0205] -- 270
|
||||||
|
[T4BRFA99H00M0206] -- 315
|
||||||
|
[T4BRFA99H00M0207] -- 0
|
||||||
|
|
||||||
|
All commands need CR added
|
||||||
|
The 98 should be replaced by whatever the rig returns -- in this case it was 99.
|
||||||
|
Startup: [LINK] returns [LINKOK]
|
||||||
|
LEFT:[R98T4AH01] [R99T4AH01] counter
|
||||||
|
RIGHT:[R98T4AH02]
|
||||||
|
UNI:[R98T4AH03] [R99T4AH03]
|
||||||
|
BI: [R98T4AH04] [R99T4AH04]
|
||||||
|
FLIP: [R98T4AH05] [R99T4AH05]
|
||||||
|
|
||||||
|
Direct switching
|
||||||
|
Seems the "98" model does not recognized the direct commands
|
||||||
|
[R99T4AM10] 0
|
||||||
|
[R99T4AM11] 45
|
||||||
|
[R99T4AM12] 90
|
||||||
|
[R99T4AM13] 135
|
||||||
|
[R99T4AM14] 180
|
||||||
|
[R99T4AM15] 225
|
||||||
|
[R99T4AM16] 270
|
||||||
|
[R99T4AM17] 315
|
||||||
|
|
||||||
|
Misc Commands
|
||||||
|
[GETVER]
|
||||||
|
<VER> response with string
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* Apex Shared Loop Controller */
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "hamlib/rotator.h"
|
||||||
|
#include "iofunc.h"
|
||||||
|
#include "apex.h"
|
||||||
|
|
||||||
|
int apex_shared_loop_get_position(ROT *rot, float *az, float *el)
|
||||||
|
{
|
||||||
|
int loop = 10;
|
||||||
|
|
||||||
|
while (--loop > 0 && apex_azimuth < 0)
|
||||||
|
{
|
||||||
|
hl_usleep(250 * 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
*az = apex_azimuth;
|
||||||
|
|
||||||
|
*el = 0;
|
||||||
|
|
||||||
|
return RIG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apex_shared_loop_set_position(ROT *rot, float az, float dummy)
|
||||||
|
{
|
||||||
|
char cmdstr[16];
|
||||||
|
int retval;
|
||||||
|
struct rot_state *rs = &rot->state;
|
||||||
|
int remainder = lround(az + 22.5) % 45;
|
||||||
|
int apex_az = lround(az + 22.5) - remainder;
|
||||||
|
|
||||||
|
// default to 0 degrees
|
||||||
|
snprintf(cmdstr, sizeof(cmdstr), "[R99T4AM10]\r\n");
|
||||||
|
|
||||||
|
switch (apex_az)
|
||||||
|
{
|
||||||
|
case 45: cmdstr[9] = '1'; break;
|
||||||
|
|
||||||
|
case 90: cmdstr[9] = '2'; break;
|
||||||
|
|
||||||
|
case 135: cmdstr[9] = '3'; break;
|
||||||
|
|
||||||
|
case 180: cmdstr[9] = '4'; break;
|
||||||
|
|
||||||
|
case 225: cmdstr[9] = '5'; break;
|
||||||
|
|
||||||
|
case 270: cmdstr[9] = '6'; break;
|
||||||
|
|
||||||
|
case 315: cmdstr[9] = '7'; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
rig_debug(RIG_DEBUG_ERR, "%s: unknown az=%d\n", __func__, apex_az);
|
||||||
|
return -RIG_EINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rig_flush(&rs->rotport);
|
||||||
|
apex_azimuth = -1;
|
||||||
|
retval = write_block(&rs->rotport, (unsigned char *) cmdstr, strlen(cmdstr));
|
||||||
|
|
||||||
|
if (retval != RIG_OK)
|
||||||
|
{
|
||||||
|
rig_debug(RIG_DEBUG_ERR, "%s: write_block error - %s\n", __func__,
|
||||||
|
rigerror(retval));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RIG_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct rot_caps apex_shared_loop_rot_caps =
|
||||||
|
{
|
||||||
|
ROT_MODEL(ROT_MODEL_APEX_SHARED_LOOP),
|
||||||
|
.model_name = "Shared Loop",
|
||||||
|
.mfg_name = "Apex",
|
||||||
|
.version = "20221224.0",
|
||||||
|
.copyright = "LGPL",
|
||||||
|
.status = RIG_STATUS_STABLE,
|
||||||
|
.rot_type = ROT_TYPE_AZIMUTH,
|
||||||
|
.port_type = RIG_PORT_SERIAL,
|
||||||
|
.serial_rate_min = 57600,
|
||||||
|
.serial_rate_max = 57600,
|
||||||
|
.serial_data_bits = 8,
|
||||||
|
.serial_stop_bits = 1,
|
||||||
|
.serial_parity = RIG_PARITY_NONE,
|
||||||
|
.serial_handshake = RIG_HANDSHAKE_NONE,
|
||||||
|
.write_delay = 0,
|
||||||
|
.post_write_delay = 0,
|
||||||
|
.timeout = 4000,
|
||||||
|
.retry = 2,
|
||||||
|
|
||||||
|
.min_az = 0.0,
|
||||||
|
.max_az = 360.0,
|
||||||
|
|
||||||
|
.rot_open = apex_open,
|
||||||
|
.get_info = apex_get_info,
|
||||||
|
.get_position = apex_shared_loop_get_position,
|
||||||
|
.set_position = apex_shared_loop_set_position,
|
||||||
|
};
|
||||||
|
|
|
@ -1337,7 +1337,6 @@ static int read_string_generic(hamlib_port_t *p,
|
||||||
* read 1 character from the rig, (check if in stop set)
|
* read 1 character from the rig, (check if in stop set)
|
||||||
* The file descriptor must have been set up non blocking.
|
* The file descriptor must have been set up non blocking.
|
||||||
*/
|
*/
|
||||||
do
|
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
|
@ -1349,7 +1348,7 @@ static int read_string_generic(hamlib_port_t *p,
|
||||||
#endif
|
#endif
|
||||||
rd_count = port_read_generic(p, &rxbuffer[total_count],
|
rd_count = port_read_generic(p, &rxbuffer[total_count],
|
||||||
expected_len == 1 ? 1 : minlen, direct);
|
expected_len == 1 ? 1 : minlen, direct);
|
||||||
// rig_debug(RIG_DEBUG_VERBOSE, "%s: read %d bytes\n", __func__, (int)rd_count);
|
// rig_debug(RIG_DEBUG_VERBOSE, "%s: read %d bytes tot=%d\n", __func__, (int)rd_count, total_count);
|
||||||
minlen -= rd_count;
|
minlen -= rd_count;
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
|
@ -1380,6 +1379,8 @@ static int read_string_generic(hamlib_port_t *p,
|
||||||
|
|
||||||
total_count += (int) rd_count;
|
total_count += (int) rd_count;
|
||||||
|
|
||||||
|
if (total_count == rxmax) break;
|
||||||
|
|
||||||
if (stopset && memchr(stopset, rxbuffer[total_count - 1], stopset_len))
|
if (stopset && memchr(stopset, rxbuffer[total_count - 1], stopset_len))
|
||||||
{
|
{
|
||||||
if (minlen == 1) { minlen = total_count; }
|
if (minlen == 1) { minlen = total_count; }
|
||||||
|
|
|
@ -91,6 +91,7 @@ DEFINE_INITROT_BACKEND(androidsensor);
|
||||||
#endif
|
#endif
|
||||||
DEFINE_INITROT_BACKEND(grbltrk);
|
DEFINE_INITROT_BACKEND(grbltrk);
|
||||||
DEFINE_INITROT_BACKEND(flir);
|
DEFINE_INITROT_BACKEND(flir);
|
||||||
|
DEFINE_INITROT_BACKEND(apex);
|
||||||
//! @endcond
|
//! @endcond
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,6 +141,7 @@ static struct
|
||||||
#endif
|
#endif
|
||||||
{ ROT_GRBLTRK, ROT_BACKEND_GRBLTRK, ROT_FUNCNAMA(grbltrk) },
|
{ ROT_GRBLTRK, ROT_BACKEND_GRBLTRK, ROT_FUNCNAMA(grbltrk) },
|
||||||
{ ROT_FLIR, ROT_BACKEND_FLIR, ROT_FUNCNAMA(flir) },
|
{ ROT_FLIR, ROT_BACKEND_FLIR, ROT_FUNCNAMA(flir) },
|
||||||
|
{ ROT_APEX, ROT_BACKEND_APEX, ROT_FUNCNAMA(apex) },
|
||||||
{ 0, NULL }, /* end */
|
{ 0, NULL }, /* end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue