Check-in [8d3a66aa88]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: user: pine tags: trunk EDITED .fossil-settings/binary-glob EDITED .fossil-settings/ignore-glob EDITED soft/JK20/build.xml ADDED soft/JK20/jni/Makefile ADDED soft/JK20/jni/foreach.sh ADDED soft/JK20/jni/rda/Makefile ADDED soft/JK20/jni/rda/RDA.c ADDED soft/JK20/jni/rda/RDA.java EDITED soft/JK20/src/Config.java ADDED soft/JK20/src/ConfigSaver.java ADDED soft/JK20/src/ControlMessage.java EDITED soft/JK20/src/JK20.java ADDED soft/JK20/src/Version.java ADDED soft/JK20/src/res/img/gbulboff.png ADDED soft/JK20/src/res/img/gbulbon.png ADDED soft/JK20/src/res/img/rbulboff.png ADDED soft/JK20/src/res/img/rbulbon.png ADDED soft/JK20/src/view/LevelView.java ADDED soft/JK20/src/view/StationListView.java ADDED soft/JK20/src/view/View.java EDITED soft/firmware/Makefile DELETED soft/firmware/lib/sys/stimer.d DELETED soft/firmware/lib/sys/uart.d DELETED soft/firmware/src/fusb/fusb.d DELETED soft/firmware/src/fusb/fusb_proto.d DELETED soft/firmware/src/fusb/fusb_reg.d DELETED soft/firmware/src/led.d DELETED soft/firmware/src/main.d DELETED soft/firmware/src/u2s.d EDITED soft/firmware/src/u2s_shared.h DELETED soft/firmware/src/util.d DELETED soft/libk20/Makefile DELETED soft/libk20/k20tool.c
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:8d3a66aa884c46a6c1d637149e6ac7c27e6bbac1
User & Date: pine 2016-05-14 00:59:11
Context
2016-05-15
13:02
user: pine tags: trunk EDITED soft/JK20/jni/rda/RDA.c EDITED soft/JK20/src/JK20.java ADDED soft/JK20/src/res/img/logo.png EDITED soft/JK20/src/view/StationListView.java EDITED soft/JK20/src/view/View.java EDITED soft/firmware/src/u2s.c check-in: 7dadf72775 user: pine tags: trunk
2016-05-14
00:59
user: pine tags: trunk EDITED .fossil-settings/binary-glob EDITED .fossil-settings/ignore-glob EDITED soft/JK20/build.xml ADDED soft/JK20/jni/Makefile ADDED soft/JK20/jni/foreach.sh ADDED soft/JK20/jni/rda/Makefile ADDED soft/JK20/jni/rda/RDA.c ADDED soft/JK20/jni/rda/RDA.java EDITED soft/JK20/src/Config.java ADDED soft/JK20/src/ConfigSaver.java ADDED soft/JK20/src/ControlMessage.java EDITED soft/JK20/src/JK20.java ADDED soft/JK20/src/Version.java ADDED soft/JK20/src/res/img/gbulboff.png ADDED soft/JK20/src/res/img/gbulbon.png ADDED soft/JK20/src/res/img/rbulboff.png ADDED soft/JK20/src/res/img/rbulbon.png ADDED soft/JK20/src/view/LevelView.java ADDED soft/JK20/src/view/StationListView.java ADDED soft/JK20/src/view/View.java EDITED soft/firmware/Makefile DELETED soft/firmware/lib/sys/stimer.d DELETED soft/firmware/lib/sys/uart.d DELETED soft/firmware/src/fusb/fusb.d DELETED soft/firmware/src/fusb/fusb_proto.d DELETED soft/firmware/src/fusb/fusb_reg.d DELETED soft/firmware/src/led.d DELETED soft/firmware/src/main.d DELETED soft/firmware/src/u2s.d EDITED soft/firmware/src/u2s_shared.h DELETED soft/firmware/src/util.d DELETED soft/libk20/Makefile DELETED soft/libk20/k20tool.c check-in: 8d3a66aa88 user: pine tags: trunk
2016-05-10
12:28
user: pine tags: trunk ADDED soft/JK20/build.xml ADDED soft/JK20/src/Config.java ADDED soft/JK20/src/DPrint.java ADDED soft/JK20/src/JK20.java EDITED soft/firmware/src/u2s.c check-in: 0e5172d98f user: pine tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to .fossil-settings/binary-glob.

1
fs/*
|
1
soft/JK20/src/res/*

Changes to .fossil-settings/ignore-glob.

28
29
30
31
32
33
34

35
36
soft/firmware/*.hxl
soft/firmware/*.obj
soft/firmware/*.rlf
soft/firmware/*.sdb
soft/firmware/*.sym
soft/firmware/*.p1
soft/firmware/*.pre

soft/libk20/k20tool








>


28
29
30
31
32
33
34
35
36
37
soft/firmware/*.hxl
soft/firmware/*.obj
soft/firmware/*.rlf
soft/firmware/*.sdb
soft/firmware/*.sym
soft/firmware/*.p1
soft/firmware/*.pre
soft/firmware/*.d
soft/libk20/k20tool

Changes to soft/JK20/build.xml.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
20
21
22
23
24
25
26





27
28
29
30
31
32
33
..
54
55
56
57
58
59
60



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    <!-- -->
    <property name="main-class" value="org.jk20.JK20"/>
    <!-- -->
    <property name="build.sysclasspath" value="last"/>
    <property environment="env" />
    <!-- -->
    <property name="src.dir"     value="src"/>
    <condition property="build.dir" value="${env.BUILD_DIR}/StAXTest/build" else="build">
        <isset property="env.BUILD_DIR"/>
    </condition>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir"     value="${build.dir}/jar"/>
    <!-- -->
    <target name="dirs">
        <mkdir dir="${classes.dir}"/>
................................................................................
    <target name="jni" if="jni.present" depends="dirs">
        <mkdir dir="${build.dir}/jni"/>
        <exec dir="jni" executable="make" failonerror="true">
            <arg value="all"/>
            <env key="BUILD_DIR" value="${build.dir}"/>
            <env key="CLASSES_DIR" value="${classes.dir}"/>
        </exec>





    </target>
    <!-- -->
    <target name="compile" depends="dirs,jni">
        <condition property="javac.debug" value="true" else="false">
            <isset property="env.DEBUG"/>
        </condition>
        <echo message="DEBUG: ${javac.debug}"/>
................................................................................
    <target name="doc">
        <mkdir dir="${build.dir}/doc"/>
        <javadoc destdir="${build.dir}/doc" classpath="${src.dir}"
            Encoding="UTF-8" Locale="en_US">
            <fileset dir="${src.dir}">
                <include name="**/*.java"/>
            </fileset>



        </javadoc>
    </target>
    <!-- -->
    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>
    <!-- -->
    <target name="clean-build" depends="clean, jar"/>
    <!-- -->
    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
            <jvmarg value="-Djava.library.path=${build.dir}/jni/fft"/>
        </java>
    </target>
</project>








|







 







>
>
>
>
>







 







>
>
>



|







|




2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
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
    <!-- -->
    <property name="main-class" value="org.jk20.JK20"/>
    <!-- -->
    <property name="build.sysclasspath" value="last"/>
    <property environment="env" />
    <!-- -->
    <property name="src.dir"     value="src"/>
    <condition property="build.dir" value="${env.BUILD_DIR}/${ant.project.name}/build" else="build">
        <isset property="env.BUILD_DIR"/>
    </condition>
    <property name="classes.dir" value="${build.dir}/classes"/>
    <property name="jar.dir"     value="${build.dir}/jar"/>
    <!-- -->
    <target name="dirs">
        <mkdir dir="${classes.dir}"/>
................................................................................
    <target name="jni" if="jni.present" depends="dirs">
        <mkdir dir="${build.dir}/jni"/>
        <exec dir="jni" executable="make" failonerror="true">
            <arg value="all"/>
            <env key="BUILD_DIR" value="${build.dir}"/>
            <env key="CLASSES_DIR" value="${classes.dir}"/>
        </exec>
    </target>
    <target name="clean-jni" if="jni.present">
        <exec dir="jni" executable="make" failonerror="true">
            <arg value="clean"/>
        </exec>
    </target>
    <!-- -->
    <target name="compile" depends="dirs,jni">
        <condition property="javac.debug" value="true" else="false">
            <isset property="env.DEBUG"/>
        </condition>
        <echo message="DEBUG: ${javac.debug}"/>
................................................................................
    <target name="doc">
        <mkdir dir="${build.dir}/doc"/>
        <javadoc destdir="${build.dir}/doc" classpath="${src.dir}"
            Encoding="UTF-8" Locale="en_US">
            <fileset dir="${src.dir}">
                <include name="**/*.java"/>
            </fileset>
            <fileset dir="jni">
                <include name="**/*.java"/>
            </fileset>
        </javadoc>
    </target>
    <!-- -->
    <target name="clean" depends="clean-jni">
        <delete dir="${build.dir}"/>
    </target>
    <!-- -->
    <target name="clean-build" depends="clean, jar"/>
    <!-- -->
    <target name="run" depends="jar">
        <java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
            <jvmarg value="-Djava.library.path=${build.dir}/jni/rda"/>
        </java>
    </target>
</project>

Added soft/JK20/jni/Makefile.















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
####################################
#
#
####################################
export SH = /bin/bash
export CC = gcc
export LD = gcc
export AR = ar

ifdef DEBUG
    export CFLAGS += -g
else
    export CFLAGS += -O2
endif
export CFLAGS += -Wall

ifndef DEBUG
    export LDFLAGS += -s
endif

#export DEPFILE = depfile.mk
####################################
#
#
####################################
DIRS += rda

.PHONY: all clean
all:
	$(SH) foreach.sh $@ $(DIRS)

clean:
	$(SH) foreach.sh $@ $(DIRS)

#.PHONY: depend
#depend:
#	$(SH) foreach.sh $@ $(DIRS)


Added soft/JK20/jni/foreach.sh.









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh

####################################
#
#
####################################

if [ $# -gt 1 ]; then
    ARGS=("$@")
    DIRS=${ARGS[@]:1}

    for dir in ${DIRS}; do
        make -C ${dir} $1
        RET=$?
        if [ $RET -ne 0 ]; then
            exit $RET
        fi
    done
fi

Added soft/JK20/jni/rda/Makefile.

































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
####################
#
####################
CC = gcc
LD = gcc
####################
#
####################
TARGET = $(JNI_DIR)/librda.so

JNI_CLASS = RDA
JNI_PACKAGE = org.jk20.jni.rda
JNI_DIR = $(BUILD_DIR)/jni/rda

C_FILES += RDA.c

C_OBJS  = $(foreach obj,$(C_FILES),$(patsubst %c,$(JNI_DIR)/%o, $(obj)))
OBJS += $(C_OBJS)


####################
#
####################
LIBUSB_PREFIX = /usr


CFLAGS += -Wall
CFLAGS += -D_REENTRANT
CFLAGS += -D_POSIX_C_SOURCE 
CFLAGS += -I$(JAVA_HOME)/include
CFLAGS += -I$(JAVA_HOME)/include/linux
CFLAGS += -I$(JNI_DIR)
CFLAGS += -I$(LIBUSB_PREFIX)/include/libusb-1.0
CFLAGS += -DU2S_HOST_SIDE

LDFLAGS += -fPIC
LDFLAGS += -shared

LIBS    += -lusb-1.0

VPATH += $(LIBUSB_PREFIX)/lib
####################
#
####################
.PHONY: all clean
all: compile

$(JNI_DIR)/%.o: %.c
	$(CC) -c $(CFLAGS) -o $@ $^

.PHONY: compile jheader
compile: jheader $(TARGET)

jheader: $(JNI_CLASS).java
	mkdir -p $(JNI_DIR)
	javac -d $(CLASSES_DIR) $^
	javah -cp $(CLASSES_DIR) -o $(JNI_DIR)/$(JNI_CLASS).h $(JNI_PACKAGE).$(JNI_CLASS)

$(TARGET): $(OBJS) $(LIBS)
	$(LD) $(LDFLAGS) -o $@ $^

clean:
	rm -rf $(OBJS) $(TARGET) $(JNI_DIR)

Added soft/JK20/jni/rda/RDA.c.











































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/*
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <libusb.h>
#include <RDA.h> 
#include <arpa/inet.h> /* for htons */
#include "../../../firmware/src/u2s_shared.h"

#define DEBUG_THIS

#define FATAL_ERROR_MESSAGE    "(E) JNI RDA"

#define TIMEOUT_MS   200

#define RDA_PACKAGE   "org/jk20/jni/rda/"
#define USB_EXCEPTION RDA_PACKAGE "USBException"

libusb_context *context = NULL;
libusb_device_handle *handle = NULL;

static int _command_exec(
        struct u2s_req_t *req, int reqlen,
        struct u2s_resp_t *resp, int *resplen);
static int _send(uint8_t *buf, int len, int timeout);
static int _recv(uint8_t *buf, int len, int timeout);

/**
 *
 */
static void _throwException(JNIEnv *env, const char *exName, char *message)
{
    jclass exClass = (*env)->FindClass(env, exName);
//    jclass exception = (*env)->FindClass(env, "java/lang/Exception");
    if (!exClass)
    {
        /* NOTREACHED */
        fprintf(stderr, "Failed to find \"%s\" class\r\n", exName);
        fflush(stderr);
        return;
    }
    (*env)->ThrowNew(env, exClass, message);
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_init(JNIEnv *env, jobject thisObject)
{
    const struct libusb_version *lv;
    
    lv = libusb_get_version();
    printf("libusb version %d.%d.%d\r\n", lv->major, lv->minor, lv->micro);
    fflush(stdout);

    if (libusb_init(&context))
    {
        context = NULL;
        _throwException(env, USB_EXCEPTION, "libusb init error");
        return;
    }
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    open
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_open(JNIEnv *env, jobject thisObject)
{
    int i, cnt, ndev;
    libusb_device **devs;
    libusb_device *dev;
    int r;
    struct libusb_device_descriptor desc;

    cnt = libusb_get_device_list(context, &devs);
    if (cnt < 0)
    {
        _throwException(env, USB_EXCEPTION, "can not get divice list");
        goto error;
    }

    dev  = NULL;
    ndev = 0;
    for (i = 0; i < cnt; i++)
    {
        r = libusb_get_device_descriptor(devs[i], &desc);
        if (r < 0) {
            _throwException(env, USB_EXCEPTION, "failed to get device descriptor");
            goto error;
        }

        if (desc.idVendor == org_jk20_jni_rda_RDA_DEVICE_VID &&
                desc.idProduct == org_jk20_jni_rda_RDA_DEVICE_PID)
        {
            printf("%04x:%04x (bus %d, device %d)\n",
                    desc.idVendor, desc.idProduct,
                    libusb_get_bus_number(devs[i]), libusb_get_device_address(devs[i]));
            fflush(stdout);
            dev = devs[i];
            /* XXX only first found device */
            if (ndev == 0)
                break;
            ndev++;
        }
    }

    if (dev == NULL)
    {
        _throwException(env, USB_EXCEPTION, "can not find device");
        goto error;
    }

    if (libusb_open(dev, &handle))
    {
        _throwException(env, USB_EXCEPTION, "can not open device handle");
        goto error;
    }

    if (libusb_claim_interface(handle, 0))
    {
        _throwException(env, USB_EXCEPTION, "claim error");
        libusb_close(handle);
        handle = NULL;
        goto error;
    }

    libusb_free_device_list(devs, 1);

    /* XXX receive possible unhandled data */
    {
        unsigned char buf[64];
        _recv(buf, 64, 100);
    }

    return;
error:
    ;
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_close(JNIEnv *env, jobject thisObject)
{
    if (handle != NULL)
    {
        libusb_release_interface(handle, 0);
        libusb_close(handle);
        handle = NULL;
    }
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    destroy
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_destroy(JNIEnv *env, jobject thisObject)
{
    if (context != NULL)
        libusb_exit(context);
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    write
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_write (JNIEnv *env, jobject thisObject)
{
    jchar wbuf[org_jk20_jni_rda_RDA_REG_NUMBER];
    jclass thisClass;
    jfieldID regsID;
    jcharArray regsObject;

    if (context == NULL)
        _throwException(env, USB_EXCEPTION, "libusb not initialized");
    if (handle == NULL)
        _throwException(env, USB_EXCEPTION, "device not opened");

    thisClass = (*env)->GetObjectClass(env, thisObject);

    regsID = (*env)->GetFieldID(env, thisClass, "regs", "[C");
    if ((*env)->ExceptionCheck(env))
    {
        (*env)->ExceptionDescribe(env);
        (*env)->FatalError(env, FATAL_ERROR_MESSAGE);
        return; /* not necessary */
    }
    regsObject = (*env)->GetObjectField(env, thisObject, regsID);

    (*env)->GetCharArrayRegion(env, regsObject,
            org_jk20_jni_rda_RDA_WRITE_REG_START, org_jk20_jni_rda_RDA_REG_NUMBER, wbuf); 
    if ((*env)->ExceptionCheck(env))
    {
        (*env)->ExceptionDescribe(env);
        (*env)->FatalError(env, FATAL_ERROR_MESSAGE);
        return; /* not necessary */
    }

    /* send request */
    {
        struct u2s_req_t req; /* NOTE on stack */
        struct u2s_resp_t resp; /* NOTE on stack */
        int i;
        int n;

        req.cmd = U2S_CMD_RDA_WRITE;
        for (i = 0; i < org_jk20_jni_rda_RDA_REG_NUMBER; i++)
            req.rda_write.data16[i] = htons(wbuf[i]); /* NOTE to big-endian */

        if (_command_exec(&req, U2S_REQ_HEAD_SIZE + sizeof(union rda_write_data_t),
                    &resp, &n) != 0)
        {
            fflush(stderr);
            _throwException(env, USB_EXCEPTION, "failed to write data");
            return;
        }
    }
}

/*
 * Class:     org_jk20_jni_rda_RDA
 * Method:    read
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_jk20_jni_rda_RDA_read(JNIEnv *env, jobject thisObject)
{
    jchar rbuf[org_jk20_jni_rda_RDA_REG_NUMBER];
    jclass thisClass;
    jfieldID regsID;
    jcharArray regsObject;

    if (context == NULL)
        _throwException(env, USB_EXCEPTION, "libusb not initialized");
    if (handle == NULL)
        _throwException(env, USB_EXCEPTION, "device not opened");

    thisClass = (*env)->GetObjectClass(env, thisObject);

    regsID = (*env)->GetFieldID(env, thisClass, "regs", "[C");
    if ((*env)->ExceptionCheck(env))
    {
        (*env)->ExceptionDescribe(env);
        (*env)->FatalError(env, FATAL_ERROR_MESSAGE);
        return; /* not necessary */
    }
    regsObject = (*env)->GetObjectField(env, thisObject, regsID);

    /* send request */
    {
        struct u2s_req_t req; /* NOTE on stack */
        struct u2s_resp_t resp; /* NOTE on stack */
        int i;
        int n;

        req.cmd = U2S_CMD_RDA_READ;
        if (_command_exec(&req, U2S_REQ_HEAD_SIZE,
                    &resp, &n) != 0)
        {
            fflush(stderr);
            _throwException(env, USB_EXCEPTION, "failed to read data");
            return;
        }
        if (n != (U2S_REQ_HEAD_SIZE + sizeof(union rda_read_data_t)))
        {
            _throwException(env, USB_EXCEPTION, "not enough data received");
            return;
        }

        for (i = 0; i < org_jk20_jni_rda_RDA_REG_NUMBER; i++)
            rbuf[i] = ntohs(resp.rda_read.data16[i]); /* NOTE from big-endian */
    }

    (*env)->SetCharArrayRegion(env, regsObject,
            org_jk20_jni_rda_RDA_READ_REG_START, org_jk20_jni_rda_RDA_REG_NUMBER, rbuf);
    if ((*env)->ExceptionCheck(env))
    {
        (*env)->ExceptionDescribe(env);
        (*env)->FatalError(env, FATAL_ERROR_MESSAGE);
        return; /* not necessary */
    }
}

/*
 * Execute command.
 *
 *
 * RETURN
 *     0    success
 *     1    send error
 *     2    receive error
 */
static int _command_exec(
        struct u2s_req_t *req, int reqlen,
        struct u2s_resp_t *resp, int *resplen)
{
    int r;

    r = _send((uint8_t*)req, reqlen, TIMEOUT_MS);
    if (r < 0)
        return 1;
    if (r == 0)
    {
        fprintf(stderr, "%s, send return zero bytes\r\n", __FUNCTION__);
        return 1;
    }
    if (r != reqlen)
    {
        fprintf(stderr, "%s, not all bytes was sended\r\n", __FUNCTION__);
        return 1;
    }

    r = _recv((uint8_t*)resp, sizeof(struct u2s_resp_t), TIMEOUT_MS);
    if (r < 0)
        return 2;
    if (r == 0)
    {
        fprintf(stderr, "%s, recv return zero bytes\r\n", __FUNCTION__);
        return 2;
    }
    if (r < U2S_REQ_HEAD_SIZE)
    {
        fprintf(stderr, "%s, not enough bytes received\r\n", __FUNCTION__);
        return 2;
    }
    *resplen = r;

    if (resp->cmd == U2S_CMD_ERROR)
    {
        if (r > U2S_REQ_HEAD_SIZE)
            fprintf(stderr, "%s, device returned error %d\r\n", __FUNCTION__, resp->error);
        else
            fprintf(stderr, "%s, device returned XXX error\r\n", __FUNCTION__);
        return 2;
    }

    if (resp->cmd != req->cmd)
    {
        fprintf(stderr, "%s, command mismatch\r\n", __FUNCTION__);
        return 2;
    }

    return 0;
}


/*
 * RETURN
 *     count of bytes sended, -1 on error
 */
static int _send(uint8_t *buf, int len, int timeout)
{
    int ret;
    int n;

    ret = libusb_bulk_transfer(handle,
            LIBUSB_ENDPOINT_OUT | org_jk20_jni_rda_RDA_DEVICE_TRANSFER_ENDPOINT,
            buf, len, &n, timeout);
    if (ret)         
    {
        fprintf(stderr, "transfer (OUT) error %d\r\n", ret);
        return -1;
    }
#ifdef DEBUG_THIS 
    {
        int i;

        printf("OUT: ");
        for (i = 0; i < n; i++)
        {
            if ((i % 16 == 0))
                printf("\r\n     ");
            printf("%02hhX ", buf[i]);
        }
        printf("\r\n");
    }
#endif
    return n;
}

/*
 *
 */
static int _recv(uint8_t *buf, int len, int timeout)
{
    int ret;
    int n;

    ret = libusb_bulk_transfer(handle,
            LIBUSB_ENDPOINT_IN | org_jk20_jni_rda_RDA_DEVICE_TRANSFER_ENDPOINT,
        buf, len, &n, timeout);
    if (ret)         
    {
        fprintf(stderr, "transfer (IN) error %d\r\n", ret);
        return -1;
    }
#ifdef DEBUG_THIS
    {
        int i;

        printf(" IN: ");
        for (i = 0; i < n; i++)
        {
            if ((i % 16 == 0))
                printf("\r\n     ");
            printf("%02hhX ", buf[i]);
        }
        printf("\r\n");
    }
#endif
    return n;
}

Added soft/JK20/jni/rda/RDA.java.

































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
/*
 *
 */
package org.jk20.jni.rda;

/**
 * TODO Usage example
 * <pre>
 * </pre>
 */
public class RDA {
    private static final int DEVICE_VID = 0xffff;
    private static final int DEVICE_PID = 0x0001;
    private static final int DEVICE_TRANSFER_ENDPOINT = 0x01;

    private static final int REG_NUMBER = 6;
    private static final int WRITE_REG_START = 0x02;
    private static final int READ_REG_START  = 0x0A;
    /* 
     * NOTE
     *     Only 0x02 to 0x07 and 0x0A to 0x0x0F ranges is used by underlain layer.
     */
    private char[] regs;

    static {
        System.loadLibrary("rda");
    }
    /**
     *
     */
    public RDA() {
        regs = new char[READ_REG_START + REG_NUMBER];
    }
    /**
     * Initialize library.
     */
    public native void init() throws USBException;
    /**
     * Open device handler.
     */
    public native void open() throws USBException;
    /**
     * Close device handler.
     */
    public native void close();
    /**
     * Free resources.
     */
    public native void destroy();
    /**
     * Write data to device.
     */
    private native void write() throws USBException;
    /**
     * Read data from device.
     */
    private native void read();

    /**
     *
     */
    public void printRegs() {
        System.out.format("=== RDA regs ===%n");
        System.out.format("---- Write  ----%n");
        for (int i = WRITE_REG_START;
                i < WRITE_REG_START + REG_NUMBER; i++) {
            System.out.format("%02X %04X%n", i, (int)regs[i]);
        }
        System.out.format("---- Read   ----%n");
        for (int i = WRITE_REG_START;
                i < WRITE_REG_START + REG_NUMBER; i++) {
            System.out.format("%02X %04X%n", i, (int)regs[i]);
        }
    }

    /* reg 0x02 */
    private char wENABLE       = 0b0;
    private char wSOFT_RESET   = 0b0;
    private char wNEW_METHOD   = 0b0;
    private char wRDS_EN       = 0b0;
    public static final char wcCLK_MODE_32_768_KHZ = 0b000;
    public static final char wcCLK_MODE_12_MHZ     = 0b001;
    public static final char wcCLK_MODE_24_MHZ     = 0b101;
    public static final char wcCLK_MODE_13_MHZ     = 0b010;
    public static final char wcCLK_MODE_26_MHZ     = 0b110;
    public static final char wcCLK_MODE_19_2_MHZ   = 0b011;
    public static final char wcCLK_MODE_38_4_MHZ   = 0b111;
    private char wCLK_MODE     = wcCLK_MODE_32_768_KHZ;
    private char wSKMODE       = 0b0;
    private char wSEEK         = 0b0;
    private char wSEEKUP       = 0b0;
    private char wRCLK_DIRECT_INPUT_MODE  = 0b0;
    private char wRCLK_NON_CALIBRATE_MODE = 0b0;
    private char wBASS         = 0b0;
    private char wMONO         = 0b0;
    private char wDMUTE        = 0b0;
    private char wDHIZ         = 0b0;
    /* reg 0x03 */
    public static final char wcSPACE_100_KHZ = 0b00;
    public static final char wcSPACE_200_KHZ = 0b01;
    public static final char wcSPACE_50_KHZ  = 0b10;
    public static final char wcSPACE_25_KHZ  = 0b11;
    private char wSPACE       = wcSPACE_100_KHZ;
    public static final char wcBAND_87_108_MHZ = 0b00;
    public static final char wcBAND_76_91_MHZ  = 0b01;
    public static final char wcBAND_76_108_MHZ = 0b10;
    public static final char wcBAND_65_76_MHZ  = 0b11;
    private char wBAND        = wcBAND_76_108_MHZ;
    private char wTUNE        = 0b0;
    private char wDIRECT_MODE = 0b0;
    private char wCHAN        = 0b0000000000;
    /* reg 0x04 */
    private static final char wcGPIO1_HIGHZ = 0b00;
    private static final char wcGPIO1_LOW   = 0b10;
    private static final char wcGPIO1_HIGH  = 0b11;
    private char wGPIO1       = wcGPIO1_HIGHZ;
    private static final char wcGPIO2_HIGHZ        = 0b00;
    private static final char wcGPIO2_INT          = 0b01;
    private static final char wcGPIO2_LOW          = 0b10;
    private static final char wcGPIO2_HIGH         = 0b11;
    private char wGPIO2       = wcGPIO2_HIGHZ;
    private static final char wcGPIO3_HIGHZ        = 0b00;
    private static final char wcGPIO3_MONO_STEREO  = 0b01;
    private static final char wcGPIO3_LOW          = 0b10;
    private static final char wcGPIO3_HIGH         = 0b11;
    private char wGPIO3       = wcGPIO3_HIGHZ;
    private char wI2S_ENABLED = 0b0;
    private char wAFCD        = 0b0;
    private char wSOFTMUTE_EN = 0b1;
    private char wDE          = 0b0;
    private char wSTCIEN      = 0b0;
    /* reg 0x05 */
    public static final char wcVOLUME_MIN = 0b0000;
    public static final char wcVOLUME_MAX = 0b1111;
    private char wVOLUME       = wcVOLUME_MAX;
    private char wLNA_PORT_SEL = 0b10;
    public static final char wcSEEKTH_MIN = 0b0000;
    public static final char wcSEEKTH_MAX = 0b1111;
    private char wSEEKTH       = 0b1000;
    private char wINT_MODE     = 0b1;
    /* reg 0x06 */
    private char wR_DELY            = 0b0;
    private char wL_DELY            = 0b0;
    private char wSCLK_O_EDGE       = 0b0;
    private char wSW_O_EDGE         = 0b0;
    public static final char wcWS_STEP_48_KBPS     = 0b1000;
    public static final char wcWS_STEP_44_1_KBPS   = 0b0111;
    public static final char wcWS_STEP_32_KBPS     = 0b0110;
    public static final char wcWS_STEP_24_KBPS     = 0b0101;
    public static final char wcWS_STEP_22_05_KBPS  = 0b0100;
    public static final char wcWS_STEP_16_KBPS     = 0b0011;
    public static final char wcWS_STEP_12_KBPS     = 0b0010;
    public static final char wcWS_STEP_11_025_KBPS = 0b0001;
    public static final char wcWS_STEP_8_KBPS      = 0b0000;
    private char wI2S_SW_CNT        = wcWS_STEP_8_KBPS;
    private char wWS_I_EDGE         = 0b0;
    private char wDATA_SIGNED       = 0b0;
    private char wSCLK_I_EDGE       = 0b0;
    private char wSW_LR             = 0b1;
    private char wI2S_MODE          = 0b0;
    private char wOPEN_MODE         = 0b00;
    /* reg 0x07 */
    private char wFREQ_MODE    = 0b0;
    private char wSOFTBLEND_EN = 0b1;
    private char wSEEK_TH_OLD  = 0b000000;
    private char w65M_50M_MODE = 0b1;
    private char wTH_SOFRBLEND = 0b10000;
    /* reg 0x0A */
    private char rREADCHAN = 0b0000000000;
    private char rST       = 0b0;
    private char rBLK_E    = 0b0;
    private char rRDSS     = 0b0;
    private char rSF       = 0b0;
    private char rSTC      = 0b0;
    private char rRDSR     = 0b0;
    /* reg 0x0B */
    private char rBLERB    = 0b00;
    private char rBLERA    = 0b00;
    private char rABCD_E   = 0b0;
    private char rFM_READY = 0b0;
    private char rFM_TRUE  = 0b0;
    private static final char rcRSSI_MIN = 0b0000000;
    private static final char rcRSSI_MAX = 0b1111111;
    private char rRSSI     = 0b0;
    /* reg 0x0C */
    private char rRDSA = 0;
    /* reg 0x0D */
    private char rRDSB = 0;
    /* reg 0x0E */
    private char rRDSC = 0;
    /* reg 0x0F */
    private char rRDSD = 0;

    /**
     * Apply changes (write data to device).
     */
    public void apply() throws USBException {
        regs[0x02]  = 0;
        regs[0x02] |= (wENABLE                  & 0b1  ) << 0;
        regs[0x02] |= (wSOFT_RESET              & 0b1  ) << 1;
        regs[0x02] |= (wNEW_METHOD              & 0b1  ) << 2;
        regs[0x02] |= (wRDS_EN                  & 0b1  ) << 3;
        regs[0x02] |= (wCLK_MODE                & 0b111) << 4;
        regs[0x02] |= (wSKMODE                  & 0b1  ) << 7;
        regs[0x02] |= (wSEEK                    & 0b1  ) << 8;
        regs[0x02] |= (wSEEKUP                  & 0b1  ) << 9;
        regs[0x02] |= (wRCLK_DIRECT_INPUT_MODE  & 0b1  ) << 10;
        regs[0x02] |= (wRCLK_NON_CALIBRATE_MODE & 0b1  ) << 11;
        regs[0x02] |= (wBASS                    & 0b1  ) << 12;
        regs[0x02] |= (wMONO                    & 0b1  ) << 13;
        regs[0x02] |= (wDMUTE                   & 0b1  ) << 14;
        regs[0x02] |= (wDHIZ                    & 0b1  ) << 15;

        regs[0x03]  = 0;
        regs[0x03] |= (wSPACE       & 0b11        ) << 0;
        regs[0x03] |= (wBAND        & 0b11        ) << 2;
        regs[0x03] |= (wTUNE        & 0b1         ) << 4;
        regs[0x03] |= (wDIRECT_MODE & 0b1         ) << 5;
        regs[0x03] |= (wCHAN        & 0b1111111111) << 6;

        regs[0x04]  = 0;
        regs[0x04] |= (wGPIO1       & 0b11) << 0;
        regs[0x04] |= (wGPIO2       & 0b11) << 2;
        regs[0x04] |= (wGPIO3       & 0b11) << 4;
        regs[0x04] |= (wI2S_ENABLED & 0b1 ) << 6;
        regs[0x04] |= (wAFCD        & 0b1 ) << 8;
        regs[0x04] |= (wSOFTMUTE_EN & 0b1 ) << 9;
        regs[0x04] |= (wDE          & 0b1 ) << 11;
        regs[0x04] |= (wSTCIEN      & 0b1 ) << 14;

        regs[0x05]  = 0;
        regs[0x05] |= (wVOLUME       & 0b1111) << 0;
        regs[0x05] |= (wLNA_PORT_SEL & 0b11  ) << 6;
        regs[0x05] |= (wSEEKTH       & 0b1111) << 8;
        regs[0x05] |= (wINT_MODE     & 0b1   ) << 15;

        regs[0x06]  = 0;
        regs[0x06] |= (wR_DELY            & 0b1   ) << 0;
        regs[0x06] |= (wL_DELY            & 0b1   ) << 1;
        regs[0x06] |= (wSCLK_O_EDGE       & 0b1   ) << 2;
        regs[0x06] |= (wSW_O_EDGE         & 0b1   ) << 3;
        regs[0x06] |= (wI2S_SW_CNT        & 0b1111) << 4;
        regs[0x06] |= (wWS_I_EDGE         & 0b1   ) << 8;
        regs[0x06] |= (wDATA_SIGNED       & 0b1   ) << 9;
        regs[0x06] |= (wSCLK_I_EDGE       & 0b1   ) << 10;
        regs[0x06] |= (wSW_LR             & 0b1   ) << 11;
        regs[0x06] |= (wI2S_MODE          & 0b1   ) << 12;
        regs[0x06] |= (wOPEN_MODE         & 0b11  ) << 13;

        regs[0x07]  = 0;
        regs[0x07] |= (wFREQ_MODE    & 0b1     ) << 0;
        regs[0x07] |= (wSOFTBLEND_EN & 0b1     ) << 1;
        regs[0x07] |= (wSEEK_TH_OLD  & 0b111111) << 2;
        regs[0x07] |= (w65M_50M_MODE & 0b1     ) << 9;
        regs[0x07] |= (wTH_SOFRBLEND & 0b11111 ) << 10;

        write();
    }
    /**
     * Take state of device (read data from device).
     */
    public void take() throws Exception {
        read();

        rREADCHAN = (char)((regs[0x0A] >>> 0 ) & 0b1111111111);
        rST       = (char)((regs[0x0A] >>> 10) & 0b1         );
        rBLK_E    = (char)((regs[0x0A] >>> 11) & 0b1         );
        rRDSS     = (char)((regs[0x0A] >>> 12) & 0b1         );
        rSF       = (char)((regs[0x0A] >>> 13) & 0b1         );
        rSTC      = (char)((regs[0x0A] >>> 14) & 0b1         );
        rRDSR     = (char)((regs[0x0A] >>> 15) & 0b1         );

        rBLERB    = (char)((regs[0x0B] >>> 0 ) & 0b11        );
        rBLERA    = (char)((regs[0x0B] >>> 2 ) & 0b11        );
        rABCD_E   = (char)((regs[0x0B] >>> 4 ) & 0b1         );
        rFM_READY = (char)((regs[0x0B] >>> 7 ) & 0b1         );
        rFM_TRUE  = (char)((regs[0x0B] >>> 8 ) & 0b1         );
        rRSSI     = (char)((regs[0x0B] >>> 9 ) & 0b1111111   );

        rRDSA = regs[0x0C];
        rRDSB = regs[0x0D];
        rRDSC = regs[0x0E];
        rRDSD = regs[0x0F];

        throw new Exception("TODO read from device");
    }
    /**
     * Enable power.
     */
    public void powerEnable() {
        wENABLE = 1;
    }
    /**
     * Disable power.
     */
    public void powerDisable() {
        wENABLE = 0;
    }
    /**
     * Do soft reset.
     */
    public void softResetEnable() {
        wSOFT_RESET = 1;
    }
    /**
     * Disable soft reset.
     */
    public void softResetDisable() {
        wSOFT_RESET = 0;
    }
    /**
     * Enable new demodulation method. Can imporve receive sensitivity about 1dB.
     */
    public void newMethodEnable() {
        wNEW_METHOD = 1;
    }
    /**
     * Disable RDS/RBDS.
     */
    public void newMethodDisable() {
        wNEW_METHOD = 0;
    }
    /**
     * Enable RDS/RBDS.
     */
    public void rdsEnable() {
        wRDS_EN = 1;
    }
    /**
     * Disable RDS/RBDS.
     */
    public void rdsDisable() {
        wRDS_EN = 0;
    }
    /**
     * Set clock mode. Use following constants:
     * <br>wcCLK_MODE_32_768_KHZ
     * <br>wcCLK_MODE_12_MHZ    
     * <br>wcCLK_MODE_24_MHZ    
     * <br>wcCLK_MODE_13_MHZ    
     * <br>wcCLK_MODE_26_MHZ    
     * <br>wcCLK_MODE_19_2_MHZ  
     * <br>wcCLK_MODE_38_4_MHZ  
     */
    public void setClockMode(char value) throws ArgumentInvalidException {
        switch (value) {
            case wcCLK_MODE_32_768_KHZ: break;
            case wcCLK_MODE_12_MHZ    : break;
            case wcCLK_MODE_24_MHZ    : break;
            case wcCLK_MODE_13_MHZ    : break;
            case wcCLK_MODE_26_MHZ    : break;
            case wcCLK_MODE_19_2_MHZ  : break;
            case wcCLK_MODE_38_4_MHZ  : break;
            default:
                throw new ArgumentInvalidException("Invalid value");
        }
        wCLK_MODE = value;
    }
    /**
     * Wrap at the upper or lower band limit and continue seeking.
     */
    public void setSeekModeWrap() {
        wSKMODE = 0;
    }
    /**
     * Stop seeking at the upper or lower band limit.
     */
    public void setSeekModeStop() {
        wSKMODE = 1;
    }
    /**
     * Enable seek.
     */
    public void seekEnable() {
        wSEEK = 1;
    }
    /**
     * Disable seek.
     */
    public void seekDisable() {
        wSEEK = 0;
    }
    /**
     * Set seek direction to UP.
     */
    public void setSeekUp() {
        wSEEKUP = 1;
    }
    /**
     * Set seek direction to DOWN.
     */
    public void setSeekDown() {
        wSEEKUP = 0;
    }
    /**
     * Enable bass boost.
     */
    public void bassBoostEnable() {
        wBASS = 1;
    }
    /**
     * Disable bass boost.
     */
    public void bassBoostDisable() {
        wBASS = 0;
    }
    /**
     * Force mono.
     */
    public void monoEnable() {
        wMONO = 1;
    }
    /**
     * Stereo.
     */
    public void monoDisable() {
        wMONO = 0;
    }
    /**
     * Mute enable.
     */
    public void muteEnable() {
        wDMUTE = 0;
    }
    /**
     * Mute disable.
     */
    public void muteDisable() {
        wDMUTE = 1;
    }
    /**
     * Enable audio high impedance.
     */
    public void audioHighZEnable() {
        wDHIZ = 0;
    }
    /**
     * Disable audio high impedance - normal operation.
     */
    public void audioHighZDisable() {
        wDHIZ = 1;
    }
    /**
     * Set channel spacing. Possible values are:
     * <br>wcSPACE_100_KHZ
     * <br>wcSPACE_200_KHZ
     * <br>wcSPACE_50_KHZ 
     * <br>wcSPACE_25_KHZ 
     */
    public void setChannelSpacing(char value) throws ArgumentInvalidException {
        switch (value) {
            case wcSPACE_100_KHZ: break;
            case wcSPACE_200_KHZ: break;
            case wcSPACE_50_KHZ : break;
            case wcSPACE_25_KHZ : break;
            default:
                throw new ArgumentInvalidException("Invalid value");
        }
        wSPACE = value;
    }
    /**
     * Band select. Possible values are:
     * <br>wcBAND_87_108_MHZ
     * <br>wcBAND_76_91_MHZ 
     * <br>wcBAND_76_108_MHZ
     * <br>wcBAND_65_76_MHZ 
     */
    public void selectBand(char value) throws ArgumentInvalidException {
        switch (value) {
            case wcBAND_87_108_MHZ: break;
            case wcBAND_76_91_MHZ : break;
            case wcBAND_76_108_MHZ: break;
            case wcBAND_65_76_MHZ : break;
            default:
                throw new ArgumentInvalidException("Invalid value");
        }
        wBAND = value;
    }
    /**
     * Enable tune.
     */
    public void tuneEnable() {
        wTUNE = 1;
    }
    /**
     * Disable tune.
     */
    public void tuneDisable() {
        wTUNE = 0;
    }
    /**
     * Select channel with desired frequency.
     * @param freq Frequency to set in MHZ.
     */
    public void setChannel(double freq) throws ArgumentInvalidException, StateInvalidException {
        double space;
        double value;

        switch (wSPACE) {
            case wcSPACE_100_KHZ: space = 0.1;  break;
            case wcSPACE_200_KHZ: space = 0.2;  break;
            case wcSPACE_50_KHZ : space = 0.05; break;
            case wcSPACE_25_KHZ : space = 0.25; break;
            default:
                /* NOTREACHED */
                throw new StateInvalidException("Space has invalid value");
        }

        switch (wBAND) {
            case wcBAND_87_108_MHZ:
                if (freq < 87 || freq > 108)
                    throw new ArgumentInvalidException("Invalid value of frequency for selected BAND");
                value = (freq - 87) / space;
                break;
            case wcBAND_76_91_MHZ :
                if (freq < 76 || freq > 91)
                    throw new ArgumentInvalidException("Invalid value of frequency for selected BAND");
                /* FALLTHROUGH */
            case wcBAND_76_108_MHZ:
                if (freq < 76 || freq > 108)
                    throw new ArgumentInvalidException("Invalid value of frequency for selected BAND");
                value = (freq - 76) / space;
                break;
            case wcBAND_65_76_MHZ :
                if (freq < 65 || freq > 76)
                    throw new ArgumentInvalidException("Invalid value of frequency for selected BAND");
                value = (freq - 65) / space;
                break;
            default:
                /* NOTREACHED */
                throw new StateInvalidException("Band has invalid value");
        }

        wCHAN = (char)value;
        System.out.format("Set CHAN to %d%n", (int)wCHAN);
    }
    /**
     * Softmute enable.
     */
    public void softMuteEnable() {
        wSOFTMUTE_EN = 1;
    }
    /**
     * Softmute disable.
     */
    public void softMuteDisable() {
        wSOFTMUTE_EN = 0;
    }
    /**
     * Set volume level. Value should be between <b>RDA.wcVOLUME_MIN</b> and <b>RDA.wcVOLUME_MAX</b>.
     */
    public void setVolume(char value) {
        if (value < wcVOLUME_MIN)
            value = wcVOLUME_MIN;
        if (value > wcVOLUME_MAX)
            value = wcVOLUME_MAX;
        wVOLUME = value;
    }
    /**
     * Set seekSNR Threshold value. Value should be between <b>RDA.wcSEEKTH_MIN</b> and <b>RDA.wcSEEKTH_MAX</b>.
     */
    public void setSeekSNRThreshold(char value) {
        if (value < wcSEEKTH_MIN)
            value = wcSEEKTH_MIN;
        if (value > wcSEEKTH_MAX)
            value = wcSEEKTH_MAX;
        wSEEKTH = value;
    }

    /**
     * Get frequency of current channel
     * @return Frequency value in MHZ.
     */
    public double getChannel() throws ArgumentInvalidException, StateInvalidException {
        double space;
        double freq;

        switch (wSPACE) {
            case wcSPACE_100_KHZ: space = 0.1;  break;
            case wcSPACE_200_KHZ: space = 0.2;  break;
            case wcSPACE_50_KHZ : space = 0.05; break;
            case wcSPACE_25_KHZ : space = 0.25; break;
            default:
                /* NOTREACHED */
                throw new StateInvalidException("Space has invalid value");
        }

        switch (wBAND) {
            case wcBAND_87_108_MHZ:
                freq = rREADCHAN * space + 87;
                break;
            case wcBAND_76_91_MHZ :
                /* FALLTHROUGH */
            case wcBAND_76_108_MHZ:
                freq = rREADCHAN * space + 76;
                break;
            case wcBAND_65_76_MHZ :
                freq = rREADCHAN * space + 65;
                break;
            default:
                /* NOTREACHED */
                throw new StateInvalidException("Band has invalid value");
        }
        return freq;
    }
    /**
     * Get stereo indicator value.
     * @return true if stereo, false otherwise.
     */
    public boolean isStereo() {
        if (rST == 0)
            return false;
        else
            return true;
    }
    /**
     * Check if seek failed.
     * @return true if seek failed, false otherwise.
     */
    public boolean isSeekFail() {
        if (rSF == 0)
            return false;
        else
            return true;
    }
    /**
     * Check if seek/tune complete.
     */
    public boolean isSeekComplete() {
        if (rSTC == 1)
            return true;
        else
            return false;
    }
    /**
     * Get level of RSSI.
     * XXX Scale is logarithmic. TODO make liniar scale.
     * @return Level of RSSI in percents.
     */
    public int getRSSI() {
        return (rRSSI - rcRSSI_MIN) * 100 / rcRSSI_MAX;
    }
    /**
     *
     */
    public boolean isFMReady() {
        if (rFM_READY == 1)
            return true;
        else
            return false;
    }
    /**
     * Check if current channel is station.
     * @return true if current channel is station, false otherwise.
     */
    public boolean isChannelStation() {
        if (rFM_TRUE == 1)
            return true;
        else
            return false;
    }
}

/**
 * USB/libusb related error.
 */
class USBException extends Exception {
    public USBException(String message) {
        super(message);
    }
}
/**
 * Thrown when invalid arguments supplied to functions of this class.
 */
class ArgumentInvalidException extends Exception {
    public ArgumentInvalidException(String message) {
        super(message);
    }
}
/**
 * Thrown when fields has invalid values - should never occurred.
 */
class StateInvalidException extends Exception {
    public StateInvalidException(String message) {
        super(message);
    }
}

Changes to soft/JK20/src/Config.java.

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
...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
 */
package org.jk20;
/* */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.TreeMap;
import java.util.Map;
//import java.util.LinkedTreeMap;
import java.util.Iterator;
import java.util.Locale;
/* */
import java.awt.Color;

/* */
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
................................................................................
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.Attribute;

/**
 *
 */
public class Config {
    public TreeMap<Double, String> stationList;









    public Double currentStation;
    public Color bgColor;
    public Color fgColor;







    private static final String CONFIG_DIR = ".jk20";
    private File configPath; 
    /**
     *
     */
    public Config() {
        stationList = new TreeMap<>();
        currentStation = new Double(88.5);
        bgColor = Color.BLACK;

        fgColor = Color.WHITE;







    }
    /**
     *
     */
    public Config load() {
        Map<String, String> env = System.getenv();

................................................................................
                }
            }

            if (stationName == null)
                throw new XMLStreamException("Station has no \"name\" attribute", element.getLocation());
            if (stationValue == null)
                throw new XMLStreamException("Station has no \"value\" attribute", element.getLocation());
            stationList.put(stationValue, stationName);
        } else if (elementName.equals("config.stations.current")) {
            Double stationValue = null;
            for (SimpleAttr attr: new SimpleAttrIterator(element)) {
                if (attr.name.equals("value")) {
                    try {
                        stationValue = Double.parseDouble(attr.value);
                    } catch (Exception e) {
................................................................................
            indent++;

            xtw.writeCharacters(repeatString(INDENT, indent));
            xtw.writeEmptyElement("current");
            xtw.writeAttribute("value", String.format(Locale.US, "%.2f", currentStation));
            xtw.writeCharacters("\n");

            for (Double key: stationList.keySet()) {
                xtw.writeCharacters(repeatString(INDENT, indent));
                xtw.writeEmptyElement("station");
                xtw.writeAttribute("value", String.format(Locale.US, "%.2f", key));
                xtw.writeAttribute("name", String.format("%s", stationList.get(key)));
                xtw.writeCharacters("\n");
            }
            indent--;

            xtw.writeCharacters(repeatString(INDENT, indent--)); xtw.writeEndElement();
            xtw.writeCharacters("\n");
        }







|






>







 







|
>
>
>
>
>
>
>
>
>



>
>
>
>
>
>







|

|
>
|
>
>
>
>
>
>
>







 







|







 







|


|
|







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
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
 */
package org.jk20;
/* */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
//import java.util.LinkedTreeMap;
import java.util.Iterator;
import java.util.Locale;
/* */
import java.awt.Color;
import java.awt.Font;
/* */
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
................................................................................
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.Attribute;

/**
 *
 */
public class Config {
    public class Station {
        public Double value;
        public String name;
        public Station(Double value, String name) {
            this.value = value;
            this.name  = name;
        }
    }

    public ArrayList<Station> stationList;
    public Double currentStation;
    public Color bgColor;
    public Color fgColor;
    public Color labelColor;
    public Font labelFont;
    public Font listFont;
    public Font freqFont;
    public int windowWidth  = 640;
    public int windowHeight = 480;

    private static final String CONFIG_DIR = ".jk20";
    private File configPath; 
    /**
     *
     */
    public Config() {
        stationList = new ArrayList<>();
        currentStation = new Double(88.5);
        bgColor = new Color(0x10, 0x10, 0x20);
        fgColor = new Color(0xa0, 0xc0, 0xa0);
        labelColor = Color.WHITE;

        labelFont  = new Font(Font.MONOSPACED, Font.BOLD, 10);
        listFont   = new Font(Font.MONOSPACED, Font.BOLD, 14);
        freqFont   = new Font(Font.MONOSPACED, Font.BOLD, 20);

        windowWidth  = 640;
        windowHeight = 480;
    }
    /**
     *
     */
    public Config load() {
        Map<String, String> env = System.getenv();

................................................................................
                }
            }

            if (stationName == null)
                throw new XMLStreamException("Station has no \"name\" attribute", element.getLocation());
            if (stationValue == null)
                throw new XMLStreamException("Station has no \"value\" attribute", element.getLocation());
            stationList.add(new Station(stationValue, stationName));
        } else if (elementName.equals("config.stations.current")) {
            Double stationValue = null;
            for (SimpleAttr attr: new SimpleAttrIterator(element)) {
                if (attr.name.equals("value")) {
                    try {
                        stationValue = Double.parseDouble(attr.value);
                    } catch (Exception e) {
................................................................................
            indent++;

            xtw.writeCharacters(repeatString(INDENT, indent));
            xtw.writeEmptyElement("current");
            xtw.writeAttribute("value", String.format(Locale.US, "%.2f", currentStation));
            xtw.writeCharacters("\n");

            for (Station station: stationList) {
                xtw.writeCharacters(repeatString(INDENT, indent));
                xtw.writeEmptyElement("station");
                xtw.writeAttribute("value", String.format(Locale.US, "%.2f", station.value));
                xtw.writeAttribute("name", String.format("%s", station.name));
                xtw.writeCharacters("\n");
            }
            indent--;

            xtw.writeCharacters(repeatString(INDENT, indent--)); xtw.writeEndElement();
            xtw.writeCharacters("\n");
        }

Added soft/JK20/src/ConfigSaver.java.













































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/**
 *
 */
package org.jk20;
/* */
import java.time.Duration;
import java.time.Instant;

/**
 *
 */
public class ConfigSaver implements Runnable {
    private static int SAVE_DELAY_MS = 10 * 1000;
    private Thread thread;
    private Config config;
    private boolean save = false;
    private Instant saveTime;
    /**
     *
     */
    public ConfigSaver(Config config) {
        this.config = config;
    }
    /**
     *
     */
    public ConfigSaver start() {
        thread = new Thread(this);
        thread.setDaemon(true);
        thread.start();

        return this;
    }
    /**
     *
     */
    public void terminate() {
        thread.interrupt();
    }
    @Override
    public void run() {
        boolean interrupt = false;

        synchronized (this) {
            saveTime = Instant.now();
        }

        while (!interrupt) {
            try {
                Thread.sleep(SAVE_DELAY_MS / 2);
            } catch (InterruptedException e) {
                System.out.println(getClass().getName() + " interrupted");
                interrupt = true;
            }

            boolean proceed = false;
            synchronized (this) {
                if ((interrupt && save) || (
                            save && Duration.between(saveTime, Instant.now()).toMillis() >= SAVE_DELAY_MS))
                {
                    proceed = true;
                    save = false;
                }
            }
            if (proceed)
                saveProceed();
        }
    }
    /**
     *
     */
    public synchronized void save() {
        saveTime = Instant.now();
        save = true;
    }
    /**
     *
     */
    private void saveProceed() {
        System.out.println(getClass().getName() + " saveProceed");
        synchronized (config) {
            config.save();
        }
    }
}

Added soft/JK20/src/ControlMessage.java.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/**
 *
 */
package org.jk20;

/**
 *
 */
public class ControlMessage {
    public enum Id {
        SWITCH_TO_STATION,
        SAVE_CONFIG,
    }
    public Id id;
    public Object object;
    /**
     *
     */
    public ControlMessage(Id id, Object object) {
        this.id = id;
        this.object = object;
    }
    public ControlMessage(Id id) {
        this.id = id;
        this.object = null;
    }
}

Changes to soft/JK20/src/JK20.java.

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

/**
 *
 */
package org.jk20;








/**
 *
 */
public class JK20 {


    private static Config config;












    /**
     *
     */
    private void start(String[] args) {





        config = new Config().load();















































































//        config.save();

    }

    /**

     *





     */






























    public static void main(String[] args) {
        new JK20().start(args);

    }
}






>
>
>
>
>
>
>





>
>
|
>
>
>
>
>
>
>
|
>
>
>
>




>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>

>
|
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>

|
|
>
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
/**
 *
 */
package org.jk20;
/* */
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javax.swing.SwingUtilities;
/* */
import org.jk20.view.View;
import org.jk20.jni.rda.RDA;

/**
 *
 */
public class JK20 {
    private static RDA rda;
    private static JK20 jk20;
    public static Config config;
    private static ConfigSaver configSaver;
    public static View view;
    private static boolean terminate = false;
    private final int MESSAGE_QUEUE_CAPACITY = 16;
    private static BlockingQueue<ControlMessage> messageQueue;
    private static Thread jk20Thread;
    /**
     *
     */
    public static void main(String[] args) {
        new JK20().start(args);
    }
    /**
     *
     */
    private void start(String[] args) {
        jk20 = this;
        jk20Thread = Thread.currentThread();

        messageQueue = new ArrayBlockingQueue<ControlMessage>(MESSAGE_QUEUE_CAPACITY);

        config = new Config().load();
        configSaver = new ConfigSaver(config).start();
        SwingUtilities.invokeLater(() -> {
            view = new View();
        });

        rda = new RDA();
        try {
            rda.init();
//            rda.setChannel(88.5);
        } catch (Exception e) {
            System.out.println("RDA init error: " + e);
            terminate();
            return;
        }

//        boolean stereo = true;
        while (!needTerminate()) {
//            stereo = !stereo;
//
//            if (view != null)
//                view.setStereo(stereo);

            /* try to open device */
            try {
                rda.open();
            } catch (Exception e) {
                System.out.println("RDA open error: " + e);
                try {
                    final int RECONNECT_TIME = 2000;
                    Thread.sleep(RECONNECT_TIME);
                    continue;
                } catch (InterruptedException e2) {
                    System.out.println(getClass().getSimpleName() + " interrupted, " + e2);
                    terminate = true;
                    break;
                }
            }

            messageQueue.clear();
            while (!needTerminate()) {
                ControlMessage message;
                try {
                    message = messageQueue.take();
                } catch (InterruptedException e) {
                    System.out.println(getClass().getSimpleName() + " interrupted, " + e);
                    terminate = true;
                    break;
                }
                processMessage(message);
            }
        }
        terminate();
    }
    /**
     *
     */
    private boolean needTerminate() {
        synchronized (this) {
            return terminate;
        }
    }
    /**
     *
     */
    public void doTerminate() {
        synchronized (this) {
            terminate = true;
            jk20Thread.interrupt();
        }
    }
    /**
     *
     */
    private void processMessage(ControlMessage message) {
        switch (message.id) {
            case SWITCH_TO_STATION:
                System.out.format("Switch to station: %.2f MHz%n", (Double)message.object);
                break;
            case SAVE_CONFIG:
                configSaver.save();
                break;
        }
    }
    /**
     * Put message to queue of control thread
     */
    public void putMessage(ControlMessage.Id id) {
        putMessage(new ControlMessage(id));
    }
    /**
     * Put message to queue of control thread
     */
    public void putMessage(ControlMessage.Id id, Object object) {
        putMessage(new ControlMessage(id, object));
    }
    /**
     * Put message to queue of control thread
     */
    public void putMessage(ControlMessage message) {
        if (!messageQueue.offer(message)) {
            System.out.println("(W) " + getClass().getName() + ", queue overflow");
            try {
                messageQueue.put(message);
            } catch (InterruptedException e) {};
        }
    }
    /**
     *
     */
    public void terminate() {
        System.out.println(getClass().getName() + " terminate");

        if (rda != null) {
            rda.close();
            rda.destroy();
        }
        configSaver.terminate();
        System.exit(0);
    }
    /**
     *
     */
    public static JK20 getInstance() {

        return jk20;
    }

}

Added soft/JK20/src/Version.java.













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 *
 */
package org.jk20;

/*
 * TODO
 */

/*
 *
 */
public class Version {
    private static final int MAJOR = 0;
    private static final int MINOR = 1;
    private static final int BUILD = 0;

    public static String getString() {
        return "v" + MAJOR + "." + MINOR + "." + BUILD;
    }
}

Added soft/JK20/src/res/img/gbulboff.png.

cannot compute difference between binary files

Added soft/JK20/src/res/img/gbulbon.png.

cannot compute difference between binary files

Added soft/JK20/src/res/img/rbulboff.png.

cannot compute difference between binary files

Added soft/JK20/src/res/img/rbulbon.png.

cannot compute difference between binary files

Added soft/JK20/src/view/LevelView.java.











































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 *
 */
package org.jk20.view;
/* */
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
/* */

/*
 *
 */
public class LevelView extends JComponent {
    private Color borderColor;
    private Color fgColor;
    private Color bgColor;
    private Color bgBaseColor;
    int percents;
    /* */
    private final int BORDER_WIDTH = 1;
    private final int BAR_PAD   = 2;
    private final int BAR_WIDTH = 4;
//    private BasicStroke borderStroke;
    /**
     *
     */
    public LevelView() {
        borderColor = Color.WHITE;
        fgColor     = Color.RED;
        bgColor     = Color.BLACK;
//        borderStroke = new BasicStroke((float)BORDER_WIDTH);
        percents = 0;
    }
    /**
     *
     */
    public void setValue(int percents) {
        if (percents > 100)
            percents = 100;
        if (percents != this.percents)
        {
            this.percents = percents;
            repaint();
        }
    }
    /**
     *
     */
    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        int width = getWidth();
        int height = getHeight();

        final int MIN_HEIGHT = height / 4;
        final int NBARS      = width / (BAR_WIDTH + BAR_PAD);
        final int HINCR      = (height - MIN_HEIGHT) / NBARS;

        int nbars      = NBARS;
        int x          = (width - NBARS * (BAR_WIDTH + BAR_PAD)) / 2;
        int bheight    = MIN_HEIGHT;
        Color barColor = fgColor;

        while (nbars-- > 0) {
            /* draw bar outline */
//            g2d.setStroke(borderStroke);
            g.setColor(borderColor);
            g.fillRect(x, height - bheight,
                    BAR_WIDTH, bheight);

            if ((100 * nbars / NBARS) >= (100 - percents))
                barColor = fgColor;
            else
                barColor = bgColor;
            g.setColor(barColor);
            g.fillRect(x + BORDER_WIDTH, height - bheight + BORDER_WIDTH,
                    BAR_WIDTH - BORDER_WIDTH * 2, bheight - BORDER_WIDTH * 2);

            x += BAR_WIDTH + BAR_PAD;
            bheight += HINCR;
        }
    }
}

Added soft/JK20/src/view/StationListView.java.























































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 *
 */
package org.jk20.view;
/* */
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import java.util.Locale;
import java.util.Optional;
/* */
import org.jk20.JK20;
import org.jk20.Config;
import org.jk20.ControlMessage;

/**
 *
 */
public class StationListView {
    private JTable table;
    private StationListTableModel tableModel;
    private Config config;

    /**
     *
     */
    public StationListView() {
        this.config = JK20.getInstance().config;

        Font font;

        tableModel = new StationListTableModel();
        table = new JTable(tableModel);

        table.setShowVerticalLines(false);
        table.setShowHorizontalLines(false);
        table.setTableHeader(null);
        table.setDefaultRenderer(Object.class, new StationListTableCellRenderer());
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.setColumnSelectionAllowed(false);

        synchronized (config) {
            /* TODO set FONT from config */
            font = config.listFont;
            table.setFont(font);
            table.setBackground(config.bgColor);
            table.setForeground(config.fgColor);
            table.setSelectionBackground(Color.RED);
            table.setSelectionForeground(Color.WHITE);
        }
        table.setRowHeight(font.getSize() + 2);

        table.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
            if (e.getValueIsAdjusting())
                return;
            int selIndex = table.getSelectedRow();
            Double switchToStation;

            synchronized (config) {
                if (selIndex < 0 && selIndex >= config.stationList.size())
                    return;
                switchToStation = new Double(config.stationList.get(selIndex).value);
            }
            JK20.getInstance().putMessage(ControlMessage.Id.SWITCH_TO_STATION, switchToStation);
        });

        SwingUtilities.invokeLater(() -> {
            table.getColumnModel().getColumn(0).setMaxWidth(table.getWidth() * 4 / 5);
            table.getColumnModel().getColumn(1).setMaxWidth(table.getWidth() * 1 / 5);
        });

        /* XXX */
        SwingUtilities.invokeLater(() -> {
            selectCurrent();
        });
    }
    /**
     *
     */
    public void selectCurrent() {
        synchronized (config) {
            for (Config.Station station: config.stationList) {
                if (config.currentStation.equals(station.value)) {
                    table.setRowSelectionInterval(0, config.stationList.indexOf(station));
                    return;
                }
            }
            table.clearSelection();
        }
    }
    /**
     *
     */
    public JTable getComponent() {
        return table;
    }
    /**
     * TableModel for station list
     */
    class StationListTableModel extends AbstractTableModel {
        @Override
        public int getColumnCount() {
            return 2;
        }
        @Override
        public int getRowCount() {
            synchronized (config) {
                return config.stationList.size();
            }
        }
        @Override
        public Class getColumnClass(int column) {
            return String.class;
        }
        @Override
        public Object getValueAt(int row, int column) {
            synchronized (config) {
                if (row >= config.stationList.size())
                    return "";
                if (column == 0)
                    return config.stationList.get(row).name;
                if (column == 1)
                    return String.format(Locale.US, "%.2f", config.stationList.get(row).value);
            }
            return "";
        }
        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }
    }
    /**
     *
     */
    class StationListTableCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(
            JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column)
        {
            JLabel label = (JLabel)super.getTableCellRendererComponent(
                    table, value, isSelected, hasFocus, row, column);

            setBorder(noFocusBorder);

            return label;
        }
    }
}

Added soft/JK20/src/view/View.java.

































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/**
 *
 */
package org.jk20.view;
/* */
import java.util.Locale;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.color.*;
import javax.swing.*;
import javax.swing.tree.TreePath;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.ScrollPaneConstants;
import javax.swing.ImageIcon;
/* */
import org.jk20.JK20;
import org.jk20.ControlMessage;
import org.jk20.Config;
import org.jk20.Version;

/**
 *
 */
public class View extends JFrame {
    private final int PADDING = 4;
    private JPanel mainPanel;
    private JPanel sidePanel;
    private JPanel listPanel;
    private JScrollPane listScrollPane;
    private StationListView stationListView;
    private LevelView rssiLevel;
    private ImageIcon[] redBulb;
    private ImageIcon[] greenBulb;

    private JLabel frequencyIndicator;
    private JLabel stereoIndicator;
    private JLabel seekIndicator;
    private JLabel stationIndicator;
    
    /**
     *
     */
    public View() {
        Config config = JK20.getInstance().config;

        setName("JK20 " + Version.getString());
        setUndecorated(true);

        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        Dimension winSize;
        synchronized (config) {
            winSize = new Dimension(config.windowWidth, config.windowHeight);
        }

        setSize(winSize.width, winSize.height);
        setLocation((screenSize.width - winSize.width) / 2, (screenSize.height - winSize.height) / 2);

        redBulb = new ImageIcon[] {
            new ImageIcon(getClass().getResource("/res/img/rbulboff.png")),
            new ImageIcon(getClass().getResource("/res/img/rbulbon.png")),
        };
        greenBulb = new ImageIcon[] {
            new ImageIcon(getClass().getResource("/res/img/gbulboff.png")),
            new ImageIcon(getClass().getResource("/res/img/gbulbon.png")),
        };



//        greenBulbOff = new ImageIcon(getClass().getResource("/res/img/gbulboff.png"));
//        redBulbOn    = new ImageIcon(getClass().getResource("/res/img/rbulbon.png"));
//        greenBulbOn  = new ImageIcon(getClass().getResource("/res/img/gbulbon.png"));

        GridBagLayout mainGrid = new GridBagLayout();

        mainPanel = new JPanel();
        mainPanel.setLayout(mainGrid);
        mainPanel.setBorder(makePadding());
        mainPanel.setOpaque(true);

        /*
         * Side panel.
         */
        {
            sidePanel = new JPanel();
            sidePanel.setBorder(makePadding());
            sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.Y_AXIS));
            sidePanel.setOpaque(false);

            final int sideWidth = (int)(winSize.getWidth() / 3);
            sidePanel.setMinimumSize(new Dimension(sideWidth, 0));
//            sidePanel.setPreferredSize(new Dimension(sideWidth, 0));

//            rssiLevel = new LevelView();
//            rssiLevel.setMinimumSize(new Dimension(sideWidth, 12));
//            rssiLevel.setMaximumSize(new Dimension(sideWidth, 64));
//            rssiLevel.setPreferredSize(new Dimension(sideWidth, 24));

            JPanel freqFrame = new JPanel();
            freqFrame.setBorder(BorderFactory.createLineBorder(Color.GRAY, PADDING));
            freqFrame.setAlignmentX(LEFT_ALIGNMENT);
//            freqFrame.setMinimumSize(new Dimension(sideWidth / 2, 12));
//            freqFrame.setPreferredSize(new Dimension(sideWidth, 24));
//            freqFrame.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
            freqFrame.setOpaque(false);

            frequencyIndicator = new JLabel();
            freqFrame.add(frequencyIndicator);

            stereoIndicator   = new JLabel("Stereo" , JLabel.LEFT);
            stationIndicator  = new JLabel("Station", JLabel.LEFT);
            seekIndicator     = new JLabel("Seek"   , JLabel.LEFT);

            setStereoIndicator(false);
            setStationIndicator(false);
            setSeekIndicator(false, true);
            setFrequencyIndicator(0);

            sidePanel.add(freqFrame);
            sidePanel.add(Box.createVerticalStrut(PADDING));
            sidePanel.add(stationIndicator);
            sidePanel.add(Box.createVerticalStrut(PADDING));
            sidePanel.add(seekIndicator);
            sidePanel.add(Box.createVerticalStrut(PADDING));
            sidePanel.add(stereoIndicator);
            sidePanel.add(Box.createVerticalGlue());
//            sidePanel.add(rssiLevel);

            GridBagConstraints gridConstraint = new GridBagConstraints();
            gridConstraint.gridx   = 0;
            gridConstraint.gridy   = 0;
            gridConstraint.weightx = 1.0;
            gridConstraint.weighty = 1.0;
            gridConstraint.anchor  = GridBagConstraints.NORTH;
            gridConstraint.fill    = GridBagConstraints.BOTH;
            mainPanel.add(sidePanel, gridConstraint);
        }        

        /*
         * Station list panel.
         */
        {
            listPanel = new JPanel();
            listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS));
            listPanel.setBorder(makePadding());
            listPanel.setOpaque(false);

//            final int listWidth = (int)(winSize.getWidth() * 2 / 3);
//            listPanel.setPreferredSize(new Dimension(listWidth, Short.MAX_VALUE));

            stationListView = new StationListView();
            listScrollPane = new JScrollPane(stationListView.getComponent());
            listScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            listScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
            listScrollPane.setBorder(makePadding());
            listScrollPane.setOpaque(false);
            listScrollPane.getViewport().setOpaque(false);

            runLater(() -> {
                listScrollPane.revalidate();
                listScrollPane.repaint();
            });

            listPanel.add(listScrollPane);

            GridBagConstraints gridConstraint = new GridBagConstraints();
            gridConstraint.gridx   = 1;
            gridConstraint.gridy   = 0;
            gridConstraint.anchor  = GridBagConstraints.NORTHWEST;
            gridConstraint.fill    = GridBagConstraints.BOTH;
            mainPanel.add(listPanel, gridConstraint);
        }        
        /*
         * Set colors, fonts
         */
        synchronized (config) {
            mainPanel.setBackground(config.bgColor);
            stereoIndicator.setForeground(config.labelColor);
            stereoIndicator.setFont(config.labelFont);
            seekIndicator.setForeground(config.labelColor);
            seekIndicator.setFont(config.labelFont);
            stationIndicator.setForeground(config.labelColor);
            stationIndicator.setFont(config.labelFont);
            frequencyIndicator.setForeground(config.labelColor);
            frequencyIndicator.setFont(config.freqFont);
        }

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                JK20.getInstance().doTerminate();
            }
        });
        
        setContentPane(mainPanel);        
        setVisible(true);
    }
    /**
     *
     */
    public void setStereoIndicator(boolean stereo) {
        runLater(() -> {
            Icon icon = greenBulb[stereo ? 1 : 0];
            if (icon != stereoIndicator.getIcon()) {
                stereoIndicator.setIcon(icon);
//                stereoIndicator.repaint();
//                stereoIndicator.revalidate();
            }
        });
    }
    /**
     *
     */
    public void setSeekIndicator(boolean seekFail, boolean seekComplete) {
        runLater(() -> {
            Icon icon;
            if (seekFail)
                icon = redBulb[1];
            else
                icon = greenBulb[seekComplete ? 0 : 1];
            if (icon != seekIndicator.getIcon()) {
                seekIndicator.setIcon(icon);
//                seekIndicator.repaint();
//                seekIndicator.revalidate();
            }
        });
    }
    /**
     *
     */
    public void setStationIndicator(boolean station) {
        runLater(() -> {
            Icon icon = greenBulb[station ? 1 : 0];
            if (icon != stationIndicator.getIcon()) {
                stationIndicator.setIcon(icon);
//                stationIndicator.repaint();
//                stationIndicator.revalidate();
            }
        });
    }
    /**
     *
     */
    public void setFrequencyIndicator(double value) {
        runLater(() -> {
            String sval;

            if (value == 0)
                sval = "---.-- MHz";
            else
                sval = String.format(Locale.US, "%03.2f MHz", value);

            frequencyIndicator.setText(sval);
        });
    }

    /**
     *
     */
    private Border makePadding() {
        return BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING);
    }
    /**
     * Wrapper for run runnable in event dispatch thread
     */
    private static void runLater(Runnable runnable) {
        SwingUtilities.invokeLater(runnable);
    }
}

Changes to soft/firmware/Makefile.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
PK2CMD_FLAGS += -A3.3 # voltage

CC = xc8

CFLAGS = --chip=$(XC8_CHIP)
CFLAGS += --MSGDISABLE=1273
CFLAGS += -Ilib/sys
CFLAGS += -DTARGET
CFLAGS += --asmlist

SRC_PATH    = src
LIBSYS_PATH = lib/sys

OBJS  = $(SRC_PATH)/main.p1
OBJS += $(SRC_PATH)/led.p1







<







11
12
13
14
15
16
17

18
19
20
21
22
23
24
PK2CMD_FLAGS += -A3.3 # voltage

CC = xc8

CFLAGS = --chip=$(XC8_CHIP)
CFLAGS += --MSGDISABLE=1273
CFLAGS += -Ilib/sys

CFLAGS += --asmlist

SRC_PATH    = src
LIBSYS_PATH = lib/sys

OBJS  = $(SRC_PATH)/main.p1
OBJS += $(SRC_PATH)/led.p1

Deleted soft/firmware/lib/sys/stimer.d.

1
 lib/sys/stimer.d  lib/sys/stimer.p1:  lib/sys/stimer.c lib/sys/types.h lib/sys/sys.h lib/sys/stimer.h
<


Deleted soft/firmware/lib/sys/uart.d.

1
 lib/sys/uart.d  lib/sys/uart.p1:  lib/sys/uart.c lib/sys/uart.h lib/sys/types.h lib/sys/sys.h
<


Deleted soft/firmware/src/fusb/fusb.d.

1
 src/fusb/fusb.d  src/fusb/fusb.p1:  src/fusb/fusb.c src/fusb/../util.h lib/sys/debug.h src/fusb/fusb_reg.h src/fusb/fusb_proto.h lib/sys/uart.h lib/sys/types.h src/fusb/../u2s.h src/fusb/fusb.h
<


Deleted soft/firmware/src/fusb/fusb_proto.d.

1
 src/fusb/fusb_proto.d  src/fusb/fusb_proto.p1:  src/fusb/fusb_proto.c src/fusb/fusb_reg.h src/fusb/fusb_proto.h lib/sys/types.h
<


Deleted soft/firmware/src/fusb/fusb_reg.d.

1
 src/fusb/fusb_reg.d  src/fusb/fusb_reg.p1:  src/fusb/fusb_reg.c src/fusb/fusb_reg.h lib/sys/types.h
<


Deleted soft/firmware/src/led.d.

1
 src/led.d  src/led.p1:  src/led.c src/led.h lib/sys/debug.h lib/sys/uart.h lib/sys/types.h lib/sys/sys.h lib/sys/stimer.h
<


Deleted soft/firmware/src/main.d.

1
 src/main.d  src/main.p1:  src/main.c src/led.h lib/sys/debug.h lib/sys/uart.h src/version.h lib/sys/types.h lib/sys/sys.h src/fusb/fusb.h lib/sys/stimer.h src/u2s.h
<


Deleted soft/firmware/src/u2s.d.

1
 src/u2s.d  src/u2s.p1:  src/u2s.c src/led.h lib/sys/debug.h src/fusb/fusb_reg.h src/util.h lib/sys/uart.h lib/sys/types.h src/fusb/fusb.h src/u2s.h src/u2s_shared.h
<


Changes to soft/firmware/src/u2s_shared.h.

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
#ifndef U2S_SHARED_H
#define U2S_SHARED_H

#include <types.h>

#define HOST_ENDIAN_LITTLE       /* XXX TODO BIG ENDIAN */

/*
 * NOTE target is PIC18 micro, which have 1 byte alligment
 */
#ifndef TARGET
    #pragma pack(push, 1)
#endif

#define RDA_REGS_SIZE    (2 * 6) /* 0x02 to 0x07 for write, 0x0A to 0x0F for read; 16-bit regs, BE */

union rda_read_data_t {
    uint8 data[RDA_REGS_SIZE];
    struct {
#ifdef HOST_ENDIAN_LITTLE
        struct {
            uint8 readchan_high :2; /* 8-9 */
            uint8 st            :1; /* 10 */
            uint8 blk_e         :1; /* 11 */
            uint8 rdss          :1; /* 12 */
            uint8 sf            :1; /* 13 */
            uint8 stc           :1; /* 14 */
            uint8 rdsr          :1; /* 15 */
            /* */
            uint8 readchan_low  :8; /* 0-7 */
        } reg0a;
        struct {
            uint8 fm_true       :1; /* 8 */
            uint8 rssi          :7; /* 9-15 */
            /* */
            uint8 blerb         :2; /* 0-1 */
            uint8 blera         :2; /* 2-3 */
            uint8 abcd_e        :1; /* 4   */
            uint8 reserved      :2; /* 5-6 */
            uint8 fm_ready      :1; /* 7   */
        } reg0b;
        struct {
            uint8 rdsa_high;
            uint8 rdsa_low;
        } reg0c;
        struct {
            uint8 rdsb_high;
            uint8 rdsb_low;
        } reg0d;
        struct {
            uint8 rdsc_high;
            uint8 rdsc_low;
        } reg0e;
        struct {
            uint8 rdsd_high;
            uint8 rdsd_low;
        } reg0f;
#else
#error TODO: HOST BIG ENDIAN
#endif
    };



}


struct u2s_req_t {
#define U2S_REQ_HEAD_SIZE  1
#define U2S_MAX_DATA_SIZE     (50 /* XXX EP1_BUF_SIZE */ - U2S_REQ_HEAD_SIZE)
    uint8 cmd;

    union {
        union rda_write_data_t {
            uint8 data[RDA_REGS_SIZE];
            struct {
#ifdef HOST_ENDIAN_LITTLE
                struct {
                    uint8 seek         :1; /* 8   */
                    uint8 seekup       :1; /* 9   */
                    uint8 rclk_direct  :1; /* 10  */
                    uint8 rclk_nonclb  :1; /* 11  */
                    uint8 bass         :1; /* 12  */
                    uint8 mono         :1; /* 13  */
                    uint8 dmute        :1; /* 14  */
                    uint8 dhiz         :1; /* 15  */
                    /* */
                    uint8 enable       :1; /* 0   */
                    uint8 soft_reset   :1; /* 1   */
                    uint8 new_method   :1; /* 2   */
                    uint8 rds_en       :1; /* 3   */
#define RDA_CLK_MODE_32768_KHZ   0
#define RDA_CLK_MODE_12_MHZ      1
#define RDA_CLK_MODE_24_MHZ      5
#define RDA_CLK_MODE_13_MHZ      2
#define RDA_CLK_MODE_26_MHZ      6
#define RDA_CLK_MODE_19_2_MHZ    3
#define RDA_CLK_MODE_38_4_MHZ    7
                    uint8 clk_mode     :3; /* 4-6 */
                    uint8 skmode       :1; /* 7   */
                } reg02;
                struct {
#define RDA_SET_CHAN(preg, val) do {(preg)->chan_low = (val) & 0x03; (preg)->chan_high = (val) >> 2; } while (0);
                    uint8 chan_high    :8; /* 8-15 */
                    /* */
#define RDA_SPACE_100_KHZ  0
#define RDA_SPACE_200_KHZ  1
#define RDA_SPACE_50_KHZ   2
#define RDA_SPACE_25_KHZ   3
                    uint8 space        :2; /* 0-1 */
#define RDA_BAND_87_108_MHZ   0
#define RDA_BAND_76_91_MHZ    1
#define RDA_BAND_76_108_MHZ   2
#define RDA_BAND_65_76_MHZ    3
                    uint8 band         :2; /* 2-3 */
                    uint8 tune         :1; /* 4   */
                    uint8 direct_mode  :1; /* 5   */
                    uint8 chan_low     :2; /* 6-7 */
                } reg03;
                struct {
                    uint8 afcd         :1; /* 8   */
                    uint8 softmute_en  :1; /* 9   */
                    uint8 rsvd0        :1; /* 10  */
                    uint8 de           :1; /* 11  */
                    uint8 rsvd1        :2; /* 12-13 */
                    uint8 stcien       :1; /* 14   */
                    uint8 rsvd2        :1; /* 15   */
                    /* */
#define RDA_GPIO1_MODE_HIGHZ    0
#define RDA_GPIO1_MODE_RESERVED 1
#define RDA_GPIO1_MODE_LOW      2
#define RDA_GPIO1_MODE_HIGH     3
                    uint8 gpio1        :2; /* 0-1 */
#define RDA_GPIO2_MODE_HIGHZ    0
#define RDA_GPIO2_MODE_INT      1
#define RDA_GPIO2_MODE_LOW      2
#define RDA_GPIO2_MODE_HIGH     3
                    uint8 gpio2        :2; /* 2-3 */
#define RDA_GPIO3_MODE_HIGHZ       0
#define RDA_GPIO3_MODE_MONO_STEREO 1
#define RDA_GPIO3_MODE_LOW         2
#define RDA_GPIO3_MODE_HIGH        3
                    uint8 gpio3        :2; /* 4-5 */
                    uint8 i2s_enabled  :1; /* 6   */
                    uint8 rsvd         :1; /* 7   */
                } reg04;
                struct {
                    /* */
                    uint8 seekth       :4; /* 8-11  */
                    uint8 rsvd         :3; /* 12-14 */
                    uint8 int_mode     :1; /* 15    */
#define RDA_VOLUME_MAX    15
                    uint8 volume       :4; /* 0-3  */
                    uint8 rsvd0        :2; /* 4-5  */
                    uint8 lna_port_sel :2; /* 6-7  */
                } reg05;
                struct {
                    uint8 ws_i_edge    :1; /* 8  */
                    uint8 data_signed  :1; /* 9  */
                    uint8 sclk_i_edge  :1; /* 10 */
                    uint8 sw_lr        :1; /* 11 */
                    uint8 i2s_mode     :1; /* 12 */
                    uint8 open_mode    :2; /* 13-14 */
                    uint8 rsvd         :1; /* 15 */
                    /* */
                    uint8 r_dely       :1; /* 0 */
                    uint8 l_dely       :1; /* 1 */
                    uint8 sclk_o_edge  :1; /* 2 */
                    uint8 sw_o_edge    :1; /* 3 */
#define RDA_WS_STEP_8_KBPS         0
#define RDA_WS_STEP_11_025_KBPS    1
#define RDA_WS_STEP_12_KBPS        2
#define RDA_WS_STEP_16_KBPS        3
#define RDA_WS_STEP_22_05_KBPS     4
#define RDA_WS_STEP_24_KBPS        5
#define RDA_WS_STEP_32_KBPS        6
#define RDA_WS_STEP_44_1_KBPS      7
#define RDA_WS_STEP_48_KBPS        8
                    uint8 i2s_sw_cnt   :4; /* 4-7 */
                } reg06;
                struct {
                    uint8 rsvd0         :1; /* 8     */
                    uint8 _65m_50m_mode :1; /* 9     */
                    uint8 th_sofrblend  :5; /* 10-14 */
                    uint8 rsvd1         :1; /* 15    */
                    /* */
                    uint8 freq_mode    :1; /* 0      */
                    uint8 softblend_en :1; /* 1      */
                    uint8 seek_th_old  :6; /* 2      */
                } reg07;
#else
    #error TODO: HOST BIG ENDIAN
#endif
            };
        } rda_write;
        uint8 buf[U2S_MAX_DATA_SIZE];
    };
};

struct u2s_resp_t {
    uint8 cmd;

    union {
        union rda_read_data_t rda_read;
        uint8 error;
        uint8 buf[U2S_MAX_DATA_SIZE];
    };
};

#define U2S_CMD_RDA_WRITE    0x01
#define U2S_CMD_RDA_READ     0x02
#define U2S_CMD_ERROR        0xFF

#define U2S_ERROR_CMDUNKNOWN       1
#define U2S_ERROR_CMDLENMISMATCH   2
#define U2S_ERROR_I2C_NACK         3

#ifndef TARGET
    #pragma pack(pop)
#endif

#endif




|
<
<




|



|
>

<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
>
>
|

<



|


|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|




|



|
|











|





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
#ifndef U2S_SHARED_H
#define U2S_SHARED_H

#include <stdint.h>



/*
 * NOTE target is PIC18 micro, which have 1 byte alligment
 */
#ifdef U2S_HOST_SIDE
    #pragma pack(push, 1)
#endif

#define RDA_REG_NUMBER    6 /* 0x02 to 0x07 for write, 0x0A to 0x0F for read; 16-bit regs, BE */
/* NOTE RDA has big-endian byte sequence on i2c read/write */
union rda_read_data_t {

    uint8_t  data8[RDA_REG_NUMBER * 2];
    uint16_t data16[RDA_REG_NUMBER];








































};
union rda_write_data_t {
    uint8_t  data8[RDA_REG_NUMBER * 2];
    uint16_t data16[RDA_REG_NUMBER];
};


struct u2s_req_t {
#define U2S_REQ_HEAD_SIZE  1
#define U2S_MAX_DATA_SIZE     (50 /* XXX EP1_BUF_SIZE */ - U2S_REQ_HEAD_SIZE)
    uint8_t cmd;

    union {
        union rda_write_data_t rda_write;

























































































































        uint8_t buf[U2S_MAX_DATA_SIZE];
    };
};

struct u2s_resp_t {
    uint8_t cmd;

    union {
        union rda_read_data_t rda_read;
        uint8_t error;
        uint8_t buf[U2S_MAX_DATA_SIZE];
    };
};

#define U2S_CMD_RDA_WRITE    0x01
#define U2S_CMD_RDA_READ     0x02
#define U2S_CMD_ERROR        0xFF

#define U2S_ERROR_CMDUNKNOWN       1
#define U2S_ERROR_CMDLENMISMATCH   2
#define U2S_ERROR_I2C_NACK         3

#ifdef U2S_HOST_SIDE
    #pragma pack(pop)
#endif

#endif

Deleted soft/firmware/src/util.d.

1
 src/util.d  src/util.p1:  src/util.c lib/sys/debug.h src/util.h lib/sys/uart.h lib/sys/types.h
<


Deleted soft/libk20/Makefile.

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
#
#
#

K20TOOL = k20tool

CC = gcc
LD = gcc

CFLAGS  += -Wall

#LDFLAGS +=

#
#
#
.PHONY: all clean
all: $(K20TOOL)

#
#
#
K20TOOL_CFLAGS  += $(CFLAGS)
K20TOOL_LDFLAGS += $(LDFLAGS)

K20TOOL_OBJS += k20tool.c

k20tool.o: k20tool.c
	$(CC) -c $(K20TOOL_CFLAGS) $^

K20TOOL: k20tool.o
	$(LD) $(K20TOOL_LDFLAGS) -o $@

clean:
	rm -f $(K20TOOL) *.o

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































Deleted soft/libk20/k20tool.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

/*
 *
 */
int main(int argc, char** argv)
{
    printf("Hello\r\n");


    return 0;
}

<
<
<
<
<
<
<
<
<
<
<
<
<