提交SMOD ATSC IMX APP版本 V122
This commit is contained in:
Executable
+187
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Console control through a FIFO.
|
||||
*
|
||||
* Usage from a shell:
|
||||
* echo "freq 473" > /tmp/atsc_ctrl
|
||||
* echo "rxfreq 473" > /tmp/atsc_ctrl
|
||||
* echo "status" > /tmp/atsc_ctrl
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../inc/type.h"
|
||||
#include "../inc/lcd_task.h"
|
||||
#include "../inc/i2c_drv.h"
|
||||
#include "../inc/eeprom.h"
|
||||
#include "../inc/dac38j82.h"
|
||||
#include "../inc/console_ctrl.h"
|
||||
|
||||
#define ATSC_CTRL_FIFO "/tmp/atsc_ctrl"
|
||||
|
||||
static int mhz_to_chn(uint32 mhz)
|
||||
{
|
||||
uint32 chn;
|
||||
|
||||
for(chn = FREQ_MIN_V1; chn <= FREQ_MAX_ALL; chn++)
|
||||
{
|
||||
if(txfreq_to_hz(chn) == mhz)
|
||||
return (int)chn;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void save_tx_freq(uint8 chn)
|
||||
{
|
||||
int changed = (atsc_para.rf_para.txfreq != chn) ? 1 : 0;
|
||||
|
||||
atsc_para.rf_para.txfreq = chn;
|
||||
atsc_para.we_para.ch = chn;
|
||||
e2rom_read_leak(chn, &atsc_para.we_para);
|
||||
fpga_save_we(&atsc_para.we_para);
|
||||
c256_bytewrite(EEPROM_CHANNEL_ADDR, atsc_para.rf_para.txfreq);
|
||||
#if BAK_PARA_CHECK
|
||||
c256_bytewrite2(BAK_EEPROM_CHANNEL_ADDR, atsc_para.rf_para.txfreq);
|
||||
#endif
|
||||
|
||||
chang_freq(1, changed);
|
||||
}
|
||||
|
||||
static void save_rx_freq(uint8 chn)
|
||||
{
|
||||
#if USE_TUNER
|
||||
uint8 bak_tuner_freq = atsc_para.rf_para.rxfreq;
|
||||
#endif
|
||||
|
||||
atsc_para.rf_para.rxfreq = chn;
|
||||
|
||||
#if USE_TUNER
|
||||
if(bak_tuner_freq != atsc_para.rf_para.rxfreq)
|
||||
tuner_init(atsc_para.rf_para.rxfreq);
|
||||
#endif
|
||||
|
||||
c256_bytewrite(EEPROM_RXCHANNEL_ADDR, atsc_para.rf_para.rxfreq);
|
||||
#if BAK_PARA_CHECK
|
||||
c256_bytewrite2(BAK_EEPROM_RXCHANNEL_ADDR, atsc_para.rf_para.rxfreq);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void exec_cmd(char *line)
|
||||
{
|
||||
char a0[32] = {0};
|
||||
char a1[32] = {0};
|
||||
int n = sscanf(line, "%31s %31s", a0, a1);
|
||||
|
||||
if(n < 1)
|
||||
return;
|
||||
|
||||
if((strcmp(a0, "freq") == 0) && (n >= 2))
|
||||
{
|
||||
uint32 mhz = (uint32)strtoul(a1, NULL, 0);
|
||||
int chn = mhz_to_chn(mhz);
|
||||
|
||||
if(chn < 0)
|
||||
{
|
||||
printf("[atsc_ctrl] freq %u MHz invalid\n", mhz);
|
||||
return;
|
||||
}
|
||||
|
||||
save_tx_freq((uint8)chn);
|
||||
printf("[atsc_ctrl] freq %u MHz -> chn %d done\n", mhz, chn);
|
||||
}
|
||||
else if((strcmp(a0, "rxfreq") == 0) && (n >= 2))
|
||||
{
|
||||
uint32 mhz = (uint32)strtoul(a1, NULL, 0);
|
||||
int chn = mhz_to_chn(mhz);
|
||||
|
||||
if(chn < 0)
|
||||
{
|
||||
printf("[atsc_ctrl] rxfreq %u MHz invalid\n", mhz);
|
||||
return;
|
||||
}
|
||||
|
||||
save_rx_freq((uint8)chn);
|
||||
printf("[atsc_ctrl] rxfreq %u MHz -> chn %d done\n", mhz, chn);
|
||||
}
|
||||
else if(strcmp(a0, "status") == 0)
|
||||
{
|
||||
printf("[atsc_ctrl] tx=%u MHz(chn=%u) rx=%u MHz(chn=%u) rf=%u power=%u db=%u\n",
|
||||
txfreq_to_hz(atsc_para.rf_para.txfreq),
|
||||
atsc_para.rf_para.txfreq,
|
||||
txfreq_to_hz(atsc_para.rf_para.rxfreq),
|
||||
atsc_para.rf_para.rxfreq,
|
||||
atsc_para.rf_para.rf,
|
||||
atsc_para.rf_para.power,
|
||||
atsc_para.rf_para.db);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[atsc_ctrl] usage: freq <MHz> | rxfreq <MHz> | status\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void *console_ctrl_thr(void *arg)
|
||||
{
|
||||
char line[256];
|
||||
int fd;
|
||||
FILE *fp;
|
||||
|
||||
(void)arg;
|
||||
|
||||
unlink(ATSC_CTRL_FIFO);
|
||||
if((mkfifo(ATSC_CTRL_FIFO, 0666) != 0) && (errno != EEXIST))
|
||||
printf("[atsc_ctrl] mkfifo %s err=%d\n", ATSC_CTRL_FIFO, errno);
|
||||
|
||||
chmod(ATSC_CTRL_FIFO, 0666);
|
||||
printf("[atsc_ctrl] console_ctrl up, FIFO=%s\n", ATSC_CTRL_FIFO);
|
||||
|
||||
fd = open(ATSC_CTRL_FIFO, O_RDWR);
|
||||
if(fd < 0)
|
||||
{
|
||||
printf("[atsc_ctrl] open FIFO err=%d\n", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp = fdopen(fd, "r");
|
||||
if(!fp)
|
||||
{
|
||||
printf("[atsc_ctrl] fdopen FIFO err=%d\n", errno);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
line[strcspn(line, "\r\n")] = 0;
|
||||
if(line[0])
|
||||
{
|
||||
printf("[atsc_ctrl] cmd: %s\n", line);
|
||||
exec_cmd(line);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int creat_console_ctrl_thread(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
int ret = pthread_create(&tid, NULL, console_ctrl_thr, NULL);
|
||||
|
||||
if(ret != 0)
|
||||
{
|
||||
printf(" Err.[%s,%d] creat console_ctrl thread err.\n", __FUNCTION__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf(" Ok .[%s,%d] creat console_ctrl thread succeed.\n", __FUNCTION__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
Executable
+1275
File diff suppressed because it is too large
Load Diff
+1690
File diff suppressed because it is too large
Load Diff
Executable
+1624
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
@add
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#include "../inc/type.h"
|
||||
#include "../inc/delay.h"
|
||||
#include "../inc/lcd_task.h"
|
||||
#include "../inc/isys_config.h"
|
||||
#include "../inc/i2c_drv.h"
|
||||
#include "../inc/dpd_proc.h"
|
||||
#include "../inc/iuart_user.h"
|
||||
#include "../inc/eeprom.h"
|
||||
#include "../inc/gps.h"
|
||||
#include "../inc/main.h"
|
||||
#include "../inc/msg.h"
|
||||
#include "../inc/iweb_task.h"
|
||||
#include "../inc/general_api.h"
|
||||
#include "../inc/isys_com.h"
|
||||
#include "../inc/dac38j82.h"
|
||||
#include "../inc/os_task.h"
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Executable
+492
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* PR06 step5 / Task06-4: iq_rx_thr
|
||||
* Receive the 10 MSPS ORx IQ window the FPGA injects into eth1 (UDP 6100) and
|
||||
* turn each COMPLETE window into a Welch-averaged spectrum.
|
||||
*
|
||||
* Wire format: 8-byte app header + 256 complex samples, 4 bytes each,
|
||||
* big-endian: I[15:8] I[7:0] Q[15:8] Q[7:0].
|
||||
* hdr[0..1] = 'I','Q' hdr[2] = window_id hdr[4..5] = pkt_idx (0..1023)
|
||||
* hdr[6] = fmt = 2 (16-bit IQ)
|
||||
* One window = 1024 packets = 262144 samples = 26.21 ms = 1.08 ATSC fields.
|
||||
*
|
||||
* *** Why two threads (Task06-4) ***
|
||||
* The old single-loop version ran a 256-point FFT plus 256 cosf() calls inside
|
||||
* the recvfrom() loop. At 5132 pkt/s the imx6 could not keep up: the socket
|
||||
* reported drops=3810261 and only 310..930 of every 1024 packets were ever
|
||||
* processed, so the app never saw a contiguous window and could not span an
|
||||
* ATSC field. Now the RX thread does nothing but recvfrom + memcpy into a
|
||||
* window buffer (~5.6 MB/s), and a worker thread computes the spectrum of a
|
||||
* finished window out of band, double-buffered.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "iq_rx.h"
|
||||
#include "../inc/config.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define IQ_NF 256 /* samples per packet */
|
||||
#define IQ_NPKT 1024 /* packets per window (must match ram2_iq_ctrl) */
|
||||
#define IQ_PORT 6100
|
||||
#define IQ_FS_MHZ 10.0f
|
||||
#define IQ_PAY (IQ_NF * 4) /* 1024 payload bytes per packet */
|
||||
#define IQ_WBYTES (IQ_NPKT * IQ_PAY) /* 1 MiB per window */
|
||||
|
||||
/* Welch over the whole window. The FFT is 4096 points because at 10 MSPS that is
|
||||
* a 2441.40625 Hz bin -- bit for bit the same bin the FPGA's imd_imd_fft_meas uses
|
||||
* at 40 MHz/16384. So bins 10 / +1290 / -1290 land exactly on its cent/L/R taps and
|
||||
* UIMD/LIMD can be recomputed here without redefining anything. The published trace
|
||||
* is folded down to 1024 points (4 bins each) to keep the JSON small. */
|
||||
#define IQ_FFT 4096
|
||||
#define IQ_SEGPKT (IQ_FFT / IQ_NF) /* 16 packets per segment */
|
||||
#define IQ_NSEG (IQ_NPKT / IQ_SEGPKT)
|
||||
#define IQ_OUT 1024 /* published trace points */
|
||||
#define IQ_FOLD (IQ_FFT / IQ_OUT)
|
||||
|
||||
/* imd_imd_fft_meas taps: cent = +24.414 kHz, L = +3.1494 MHz, R = -3.1494 MHz.
|
||||
* HALF widens each tap to 11 bins (+-12.2 kHz): a single 2.4 kHz bin of a data
|
||||
* signal is chi-square with 2 dof, i.e. +-8 dB of scatter, and the -3.1494 MHz bin
|
||||
* additionally sits on a narrow feature ~5 dB above its neighbours. */
|
||||
#define IMD_CENT 10
|
||||
#define IMD_L 1290
|
||||
#define IMD_R (IQ_FFT - IMD_L)
|
||||
#define IMD_HALF 5
|
||||
|
||||
#define IQ_JSON "/tmp/iq_spectrum.json"
|
||||
#define IQ_JSON_TMP "/tmp/iq_spectrum.json.tmp"
|
||||
/* /tmp is tmpfs here, but a 1 MiB dump every 170 ms is pure waste; ~2 s is plenty
|
||||
* for the PC-side pull described in Result06-5. */
|
||||
#define IQ_RAW_EVERY 12
|
||||
|
||||
/* The 8VSB demod is expensive (seconds, not milliseconds -- see iq_vsb.c). It runs on
|
||||
* its own low-priority thread off a private copy of the window, so a slow demod can
|
||||
* never stall the spectrum worker or the RX socket. Hand it a window only when it is
|
||||
* idle; skipped windows cost nothing. */
|
||||
#define IQ_VSB_EVERY 6
|
||||
|
||||
/* ---- double-buffered window between the RX thread and the worker ---- */
|
||||
static unsigned char iq_win[2][IQ_WBYTES];
|
||||
static unsigned char iq_seen[2][IQ_NPKT];
|
||||
static pthread_mutex_t iq_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t iq_cond = PTHREAD_COND_INITIALIZER;
|
||||
static volatile int iq_ready = -1; /* buffer index handed to the worker, -1 = none */
|
||||
static volatile int iq_ready_pkts;
|
||||
static volatile int iq_ready_run; /* longest contiguous pkt_idx run in that window */
|
||||
static volatile int iq_ready_wid;
|
||||
|
||||
/* Kept in RAM deliberately: every process start must default to OFF. */
|
||||
static volatile int iq_spec_enable;
|
||||
|
||||
/* in-place radix-2 complex FFT */
|
||||
static void iq_fft(float *re, float *im, int n)
|
||||
{
|
||||
int i, j, len; float ang, wr, wi, ur, ui, tr, ti;
|
||||
for (i = 1, j = 0; i < n; i++) {
|
||||
int bit = n >> 1;
|
||||
for (; j & bit; bit >>= 1) j ^= bit;
|
||||
j ^= bit;
|
||||
if (i < j) { tr = re[i]; re[i] = re[j]; re[j] = tr;
|
||||
ti = im[i]; im[i] = im[j]; im[j] = ti; }
|
||||
}
|
||||
for (len = 2; len <= n; len <<= 1) {
|
||||
ang = -2.0f * (float)M_PI / len; wr = cosf(ang); wi = sinf(ang);
|
||||
for (i = 0; i < n; i += len) {
|
||||
ur = 1.0f; ui = 0.0f;
|
||||
for (j = 0; j < len / 2; j++) {
|
||||
int a = i + j, b = i + j + len / 2;
|
||||
tr = re[b] * ur - im[b] * ui;
|
||||
ti = re[b] * ui + im[b] * ur;
|
||||
re[b] = re[a] - tr; im[b] = im[a] - ti;
|
||||
re[a] += tr; im[a] += ti;
|
||||
{ float nur = ur * wr - ui * wi, nui = ur * wi + ui * wr; ur = nur; ui = nui; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* longest run of consecutive packets actually received */
|
||||
static int longest_run(const unsigned char *seen)
|
||||
{
|
||||
int i, run = 0, best = 0;
|
||||
for (i = 0; i < IQ_NPKT; i++) {
|
||||
if (seen[i]) { run++; if (run > best) best = run; }
|
||||
else run = 0;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static int cmp_float(const void *a, const void *b)
|
||||
{
|
||||
float x = *(const float *)a, y = *(const float *)b;
|
||||
return (x < y) ? -1 : (x > y);
|
||||
}
|
||||
|
||||
/* ---- newest UIMD/LIMD, published to lcd_task.c's get_tsnr_limd_uimd() ---- */
|
||||
static pthread_mutex_t imd_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static float imd_l_db, imd_u_db;
|
||||
static time_t imd_stamp; /* 0 = nothing measured yet */
|
||||
|
||||
int iq_get_imd(float *limd_db, float *uimd_db)
|
||||
{
|
||||
int fresh;
|
||||
if (!iq_spec_get_enable()) return 0;
|
||||
pthread_mutex_lock(&imd_mtx);
|
||||
fresh = imd_stamp && (time(NULL) - imd_stamp) <= IQ_IMD_MAX_AGE;
|
||||
if (fresh) { *limd_db = imd_l_db; *uimd_db = imd_u_db; }
|
||||
pthread_mutex_unlock(&imd_mtx);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
/* ---- private hand-off to the 8VSB demod thread ---- */
|
||||
static unsigned char vsb_win[IQ_WBYTES];
|
||||
static pthread_mutex_t vsb_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t vsb_cond = PTHREAD_COND_INITIALIZER;
|
||||
static volatile int vsb_pending; /* 1 = vsb_win holds a window to analyse */
|
||||
static volatile int vsb_wid;
|
||||
|
||||
int iq_spec_get_enable(void)
|
||||
{
|
||||
return iq_spec_enable != 0;
|
||||
}
|
||||
|
||||
void iq_spec_set_enable(int enable)
|
||||
{
|
||||
enable = enable ? 1 : 0;
|
||||
if (iq_spec_enable == enable) return;
|
||||
|
||||
iq_spec_enable = enable;
|
||||
if (!enable) {
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
iq_ready = -1;
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
|
||||
pthread_mutex_lock(&vsb_mtx);
|
||||
vsb_pending = 0;
|
||||
pthread_mutex_unlock(&vsb_mtx);
|
||||
|
||||
pthread_mutex_lock(&imd_mtx);
|
||||
imd_stamp = 0;
|
||||
pthread_mutex_unlock(&imd_mtx);
|
||||
iq_vsb_clear_results();
|
||||
|
||||
unlink(IQ_JSON);
|
||||
unlink(IQ_JSON_TMP);
|
||||
unlink("/tmp/iq_eye.json");
|
||||
}
|
||||
printf("[iq_rx] spectrum %s\n", enable ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
static void *iq_vsb_thr(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
#if USE_UI_RESPONSE_PRIORITY
|
||||
if (setpriority(PRIO_PROCESS, 0, 10) != 0)
|
||||
printf("[sched] iq_vsb_thr nice 10 failed: %s\n", strerror(errno));
|
||||
#else
|
||||
nice(5); /* never outrank the RX socket or TSoIP */
|
||||
#endif
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&vsb_mtx);
|
||||
while (!vsb_pending) pthread_cond_wait(&vsb_cond, &vsb_mtx);
|
||||
pthread_mutex_unlock(&vsb_mtx);
|
||||
|
||||
if (!iq_spec_get_enable()) continue;
|
||||
iq_vsb_analyse(vsb_win, vsb_wid);
|
||||
|
||||
if (!iq_spec_get_enable()) {
|
||||
iq_vsb_clear_results();
|
||||
unlink("/tmp/iq_eye.json");
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&vsb_mtx);
|
||||
vsb_pending = 0;
|
||||
pthread_mutex_unlock(&vsb_mtx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mean power of the 2*half+1 bins centred on k, wrapping the FFT index */
|
||||
static float band_power(const float *psd, int k, int half)
|
||||
{
|
||||
float acc = 0.0f;
|
||||
int d;
|
||||
for (d = -half; d <= half; d++) acc += psd[(k + d) & (IQ_FFT - 1)];
|
||||
return acc / (2 * half + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Welch-average one window and publish it as JSON for sys_spectrum.html.
|
||||
*
|
||||
* The dB reference is the mean in-band flat power density (|f| < 2.5 MHz, which
|
||||
* excludes the -2.69 MHz pilot). Result06-5 §7 explains why: referencing the
|
||||
* pilot peak makes every number a function of the FFT length, because the pilot
|
||||
* is a CW line while the shoulder is a noise density. rel-flat is RBW-invariant.
|
||||
*/
|
||||
static void *iq_spec_thr(void *arg)
|
||||
{
|
||||
static float hann[IQ_FFT];
|
||||
static float psd[IQ_FFT];
|
||||
static float re[IQ_FFT], im[IQ_FFT];
|
||||
static float sh[IQ_FFT];
|
||||
static char json[24576];
|
||||
int i, s, buf, npkt, run, wid, nseg, nraw = 0, nvsb = 0;
|
||||
|
||||
for (i = 0; i < IQ_FFT; i++)
|
||||
hann[i] = 0.5f * (1.0f - cosf(2.0f * (float)M_PI * i / (IQ_FFT - 1)));
|
||||
|
||||
(void)arg;
|
||||
#if USE_UI_RESPONSE_PRIORITY
|
||||
if (setpriority(PRIO_PROCESS, 0, 10) != 0)
|
||||
printf("[sched] iq_spec_thr nice 10 failed: %s\n", strerror(errno));
|
||||
#endif
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
while (iq_ready < 0) pthread_cond_wait(&iq_cond, &iq_mtx);
|
||||
buf = iq_ready; npkt = iq_ready_pkts; run = iq_ready_run; wid = iq_ready_wid;
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
|
||||
if (!iq_spec_get_enable()) {
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
iq_ready = -1;
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < IQ_FFT; i++) psd[i] = 0.0f;
|
||||
nseg = 0;
|
||||
for (s = 0; s < IQ_NSEG; s++) {
|
||||
const unsigned char *base = iq_win[buf] + (size_t)s * IQ_FFT * 4;
|
||||
float mr = 0, mi = 0;
|
||||
int p, drop = 0;
|
||||
for (p = 0; p < IQ_SEGPKT; p++) if (!iq_seen[buf][s * IQ_SEGPKT + p]) drop = 1;
|
||||
if (drop) continue; /* never average a torn segment */
|
||||
for (i = 0; i < IQ_FFT; i++) {
|
||||
const unsigned char *q = base + i * 4;
|
||||
re[i] = (float)(short)((q[0] << 8) | q[1]);
|
||||
im[i] = (float)(short)((q[2] << 8) | q[3]);
|
||||
mr += re[i]; mi += im[i];
|
||||
}
|
||||
mr /= IQ_FFT; mi /= IQ_FFT; /* strip the DC/LO leakage term */
|
||||
for (i = 0; i < IQ_FFT; i++) {
|
||||
re[i] = (re[i] - mr) * hann[i];
|
||||
im[i] = (im[i] - mi) * hann[i];
|
||||
}
|
||||
iq_fft(re, im, IQ_FFT);
|
||||
for (i = 0; i < IQ_FFT; i++) psd[i] += re[i] * re[i] + im[i] * im[i];
|
||||
nseg++;
|
||||
}
|
||||
if (nseg == 0) { pthread_mutex_lock(&iq_mtx); iq_ready = -1;
|
||||
pthread_mutex_unlock(&iq_mtx); continue; }
|
||||
if (!iq_spec_get_enable()) {
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
iq_ready = -1;
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
const float df = IQ_FS_MHZ / IQ_FFT; /* 2.44140625 kHz, == FPGA's 40MHz/16384 */
|
||||
const float dfo = df * IQ_FOLD; /* published bin */
|
||||
float flat = 0.0f, pk = 0.0f, pilot = 0.0f, shoulder = 0.0f;
|
||||
float p_cent, p_hi, p_lo, limd, uimd;
|
||||
int nflat = 0, nsh = 0, pkbin = 0, pos = 0, j;
|
||||
|
||||
for (i = 0; i < IQ_FFT; i++) {
|
||||
float f = (i < IQ_FFT / 2 ? i : i - IQ_FFT) * df;
|
||||
psd[i] /= nseg;
|
||||
if (f > -2.5f && f < 2.5f) { flat += psd[i]; nflat++; }
|
||||
if (psd[i] > pk) { pk = psd[i]; pkbin = i; }
|
||||
}
|
||||
flat = (nflat ? flat / nflat : 1e-12f) + 1e-12f;
|
||||
pilot = (pkbin < IQ_FFT / 2 ? pkbin : pkbin - IQ_FFT) * df;
|
||||
|
||||
/* UIMD/LIMD on imd_imd_fft_meas's own taps, band-averaged.
|
||||
* LIMD is by definition the shoulder on the pilot's side of the carrier,
|
||||
* so key it off the measured pilot rather than off a hard-coded sign: an
|
||||
* inverted ORx spectrum then swaps the taps instead of the labels. */
|
||||
p_cent = band_power(psd, IMD_CENT, IMD_HALF);
|
||||
p_hi = band_power(psd, IMD_L, IMD_HALF); /* +3.1494 MHz */
|
||||
p_lo = band_power(psd, IMD_R, IMD_HALF); /* -3.1494 MHz */
|
||||
if (pilot > 0) { float t = p_hi; p_hi = p_lo; p_lo = t; }
|
||||
limd = 10.0f * log10f(p_cent / (p_lo + 1e-12f) + 1e-12f);
|
||||
uimd = 10.0f * log10f(p_cent / (p_hi + 1e-12f) + 1e-12f);
|
||||
|
||||
pthread_mutex_lock(&imd_mtx);
|
||||
imd_l_db = limd; imd_u_db = uimd; imd_stamp = time(NULL);
|
||||
pthread_mutex_unlock(&imd_mtx);
|
||||
|
||||
/* fold 4 fine bins into one published bin; N/2 is a multiple of IQ_FOLD,
|
||||
* so a group never straddles the +-Nyquist wrap */
|
||||
for (j = 0; j < IQ_OUT; j++) {
|
||||
float acc = 0.0f;
|
||||
for (i = 0; i < IQ_FOLD; i++) acc += psd[j * IQ_FOLD + i];
|
||||
sh[j] = 10.0f * log10f(acc / IQ_FOLD / flat + 1e-12f);
|
||||
}
|
||||
for (j = 0; j < IQ_OUT; j++) psd[j] = sh[j];
|
||||
|
||||
for (j = 0; j < IQ_OUT; j++) {
|
||||
float f = (j < IQ_OUT / 2 ? j : j - IQ_OUT) * dfo;
|
||||
float a = f < 0 ? -f : f;
|
||||
if (a >= 3.5f && a <= 4.8f) sh[nsh++] = psd[j]; /* shoulder, clear of Nyquist */
|
||||
}
|
||||
if (nsh) {
|
||||
qsort(sh, nsh, sizeof(float), cmp_float);
|
||||
shoulder = sh[nsh / 2];
|
||||
}
|
||||
|
||||
pos = snprintf(json, sizeof(json),
|
||||
"{\"wid\":%d,\"pkts\":%d,\"npkt\":%d,\"run\":%d,\"ms\":%.2f,"
|
||||
"\"nseg\":%d,\"fs\":%.3f,\"n\":%d,\"f0\":%.6f,\"df\":%.6f,"
|
||||
"\"rbw_khz\":%.2f,\"pilot\":%.4f,\"peak\":%.2f,\"shoulder\":%.2f,"
|
||||
"\"limd\":%.2f,\"uimd\":%.2f,\"imd_rbw_khz\":%.3f,\"psd\":[",
|
||||
wid, npkt, IQ_NPKT, run, run * IQ_NF / (IQ_FS_MHZ * 1e3f),
|
||||
nseg, IQ_FS_MHZ, IQ_OUT, -IQ_FS_MHZ / 2.0f + 0.5f * (IQ_FOLD - 1) * df, dfo,
|
||||
dfo * 1000.0f, pilot, 10.0f * log10f(pk / flat + 1e-12f), shoulder,
|
||||
limd, uimd, df * 1000.0f * (2 * IMD_HALF + 1));
|
||||
/* emit fftshift-ed, i.e. ascending frequency from f0 */
|
||||
for (j = 0; j < IQ_OUT && pos < (int)sizeof(json) - 16; j++) {
|
||||
int k = (j + IQ_OUT / 2) & (IQ_OUT - 1);
|
||||
pos += snprintf(json + pos, sizeof(json) - pos, "%s%.1f",
|
||||
j ? "," : "", psd[k]);
|
||||
}
|
||||
pos += snprintf(json + pos, sizeof(json) - pos, "]}\n");
|
||||
|
||||
{ FILE *f = fopen(IQ_JSON_TMP, "w"); /* write+rename: the CGI never sees a partial file */
|
||||
if (f) { fwrite(json, 1, pos, f); fclose(f); rename(IQ_JSON_TMP, IQ_JSON); }
|
||||
}
|
||||
}
|
||||
|
||||
/* a full window is 26.21 ms = 1.08 ATSC fields; print only a short burst every 30s */
|
||||
{
|
||||
static time_t log_burst_start = 0;
|
||||
static int log_burst_count = 0;
|
||||
time_t now_sec = time(NULL);
|
||||
|
||||
if(log_burst_start == 0 || now_sec - log_burst_start >= 30) {
|
||||
log_burst_start = now_sec;
|
||||
log_burst_count = 0;
|
||||
}
|
||||
if(log_burst_count < 3) {
|
||||
printf("[iq_rx] win %d: %d/%d pkts, longest run %d pkts = %.2f ms (%s 1 field) period\n",
|
||||
wid, npkt, IQ_NPKT, run, run * IQ_NF / (IQ_FS_MHZ * 1e3f),
|
||||
(run * IQ_NF / (IQ_FS_MHZ * 1e6f) > 0.0242f) ? ">" : "<");
|
||||
log_burst_count++;
|
||||
}
|
||||
}
|
||||
if (npkt == IQ_NPKT && ++nraw >= IQ_RAW_EVERY) {
|
||||
FILE *r = fopen("/tmp/iq_raw.bin", "wb"); /* whole contiguous window, for PC-side analysis */
|
||||
if (r) { fwrite(iq_win[buf], 1, IQ_WBYTES, r); fclose(r); }
|
||||
nraw = 0;
|
||||
}
|
||||
/* The demodulator needs a torn-free window: a missing packet is a hole in the
|
||||
* middle of the symbol stream and the matched filter would smear it around.
|
||||
* Copy it aside so the demod thread can take its time. */
|
||||
if (npkt == IQ_NPKT && ++nvsb >= IQ_VSB_EVERY) {
|
||||
pthread_mutex_lock(&vsb_mtx);
|
||||
if (!vsb_pending) { /* still chewing the last one? skip */
|
||||
memcpy(vsb_win, iq_win[buf], IQ_WBYTES);
|
||||
vsb_wid = wid; vsb_pending = 1;
|
||||
pthread_cond_signal(&vsb_cond);
|
||||
nvsb = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&vsb_mtx);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
iq_ready = -1;
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *iq_rx_thr(void *arg)
|
||||
{
|
||||
int fd, n, cur = -1, buf = 0, npkt = 0, active = 0;
|
||||
struct sockaddr_in a;
|
||||
unsigned char pkt[2048];
|
||||
pthread_t spec_id;
|
||||
|
||||
(void)arg;
|
||||
#if USE_UI_RESPONSE_PRIORITY
|
||||
if (setpriority(PRIO_PROCESS, 0, 5) != 0)
|
||||
printf("[sched] iq_rx_thr nice 5 failed: %s\n", strerror(errno));
|
||||
#endif
|
||||
/* The injected frames are addressed to 192.168.2.143, which is NOT eth1's own
|
||||
* 192.168.2.200 -- without this secondary address the kernel treats them as
|
||||
* foreign unicast and never hands them to the socket. Note busybox has no bare
|
||||
* `ip`; the absolute path is required. */
|
||||
system("/sbin/ip addr add 192.168.2.143/24 dev eth1 2>/dev/null; /sbin/ip link set eth1 up 2>/dev/null");
|
||||
system("echo 4194304 > /proc/sys/net/core/rmem_max 2>/dev/null");
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) { printf("[iq_rx] socket fail\n"); return 0; }
|
||||
memset(&a, 0, sizeof(a));
|
||||
a.sin_family = AF_INET; a.sin_port = htons(IQ_PORT); a.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fd, (struct sockaddr *)&a, sizeof(a)) < 0) { printf("[iq_rx] bind %d fail\n", IQ_PORT); return 0; }
|
||||
{ int rb = 4 << 20; setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rb, sizeof(rb)); }
|
||||
|
||||
if (pthread_create(&spec_id, NULL, iq_spec_thr, NULL) != 0) {
|
||||
printf("[iq_rx] spec thread fail\n"); return 0;
|
||||
}
|
||||
{ pthread_t vsb_id;
|
||||
if (pthread_create(&vsb_id, NULL, iq_vsb_thr, NULL) != 0)
|
||||
printf("[iq_rx] vsb thread fail\n");
|
||||
else
|
||||
printf("[iq_rx] vsb demod thread started\n");
|
||||
}
|
||||
printf("[iq_rx] listening UDP %d, %d pkts/window, spectrum off-thread\n", IQ_PORT, IQ_NPKT);
|
||||
|
||||
memset(iq_seen[0], 0, IQ_NPKT);
|
||||
for (;;) {
|
||||
int wid, idx;
|
||||
if (!iq_spec_get_enable()) {
|
||||
active = 0;
|
||||
cur = -1; npkt = 0;
|
||||
memset(iq_seen[buf], 0, IQ_NPKT);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
if (!active) {
|
||||
while (recvfrom(fd, pkt, sizeof(pkt), MSG_DONTWAIT, NULL, NULL) > 0) {}
|
||||
active = 1;
|
||||
}
|
||||
n = recvfrom(fd, pkt, sizeof(pkt), 0, NULL, NULL);
|
||||
if (n < 8 + IQ_PAY) continue;
|
||||
if (pkt[0] != 0x49 || pkt[1] != 0x51 || pkt[6] != 0x02) continue; /* 'IQ', fmt=2 */
|
||||
wid = pkt[2];
|
||||
idx = ((pkt[4] & 0x03) << 8) | pkt[5];
|
||||
if (idx >= IQ_NPKT) continue;
|
||||
|
||||
if (cur < 0) cur = wid;
|
||||
if (wid != cur) { /* window boundary: hand this one off */
|
||||
int other = buf ^ 1;
|
||||
pthread_mutex_lock(&iq_mtx);
|
||||
if (iq_ready < 0) { /* worker is free -> publish, swap buffers */
|
||||
iq_ready = buf; iq_ready_pkts = npkt; iq_ready_wid = cur;
|
||||
iq_ready_run = longest_run(iq_seen[buf]);
|
||||
pthread_cond_signal(&iq_cond);
|
||||
buf = other;
|
||||
} /* else: worker still busy, reuse this buffer */
|
||||
pthread_mutex_unlock(&iq_mtx);
|
||||
memset(iq_seen[buf], 0, IQ_NPKT);
|
||||
npkt = 0; cur = wid;
|
||||
}
|
||||
/* the ONLY per-packet work: one memcpy. Everything else is off-thread. */
|
||||
memcpy(iq_win[buf] + (size_t)idx * IQ_PAY, pkt + 8, IQ_PAY);
|
||||
if (!iq_seen[buf][idx]) { iq_seen[buf][idx] = 1; npkt++; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Executable
+719
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
* iq_vsb.c -- 8VSB eye diagram + SNR from the imx6's own 10 MSPS ORx window.
|
||||
* PR06 step 5 / Task06-7. PC reference: scratchpad/vsb_mer.py.
|
||||
*
|
||||
* The whole receiver rests on two exact rationals:
|
||||
*
|
||||
* sps = fs/Rs = 1430/1539 (no sampling-frequency offset)
|
||||
* fp = Rs/4 (A/53's "309.441 kHz" is 309.4406 rounded)
|
||||
*
|
||||
* fp = Rs/4 means the channel-centred baseband the ORx captures is
|
||||
*
|
||||
* x(t) = sum_k a_k (-j)^k psi(t - kT)
|
||||
*
|
||||
* with psi a REAL root-raised-cosine whose Nyquist frequency is Rs/4 (i.e. its own
|
||||
* "symbol period" is 2T), beta = 0.1152, bandwidth +-3.0005 MHz < fs/2. So:
|
||||
*
|
||||
* - NO mixer / NCO anywhere. The derotation is the exact period-4 sequence j^k.
|
||||
* - psi*psi has Nyquist zeros at even multiples of T; the odd-multiple ISI lands on
|
||||
* the imaginary axis and Re{} kills it. Mathematically ISI-free.
|
||||
*
|
||||
* *** Order matters. *** r(t) = Re{y(t) e^{j2pi fp t}} has 5.69 MHz of bandwidth,
|
||||
* more than fs/2 = 5 MHz. But y(t) is only +-3 MHz and therefore exactly
|
||||
* reconstructible, so we interpolate the COMPLEX y(t) first and take Re() afterwards.
|
||||
* Doing it the other way round folds, and the algorithm floors at 15.7 dB no matter
|
||||
* how long the filter is (Task06-7 section 9).
|
||||
*/
|
||||
/*
|
||||
* Performance note. The build is already -O2; the first version still took 6.8 s per
|
||||
* window on the 792 MHz Cortex-A7. Two reasons, both worth remembering:
|
||||
* 1. `yi += h[m]*x[m]` is one serial dependency chain -- every VFP fmla waits ~8
|
||||
* cycles on the previous one. Four independent accumulators fix it.
|
||||
* 2. The core is already ~40% busy in softirq carrying the 45 Mbps IQ stream, so
|
||||
* this thread only ever gets a fraction of it. Hence iq_vsb runs on its own
|
||||
* low-priority thread (iq_rx.c) instead of blocking the spectrum worker.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "iq_rx.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define SYM_NUM 1430 /* sps = SYM_NUM/SYM_DEN, exact */
|
||||
#define SYM_DEN 1539
|
||||
#define PSI_TAPS 36 /* 16 taps floors at 28.8 dB, 32 at 44.6, 36 at 49.3 */
|
||||
#define PSI_HALF (PSI_TAPS / 2 - 1) /* kernel offsets run -PSI_HALF .. PSI_HALF+1 */
|
||||
#define PSI_BETA 0.1152f
|
||||
#define SPS (1430.0f / 1539.0f)
|
||||
|
||||
#define NSAMP 262144 /* one window */
|
||||
#define NSYM_MAX 282130 /* floor(NSAMP/sps) */
|
||||
#define GUARD 800 /* symbols dropped at each end */
|
||||
/* The full window is 282k symbols. 140k is 0.54 of an ATSC field: it still gives 168
|
||||
* data segments for the sync correlation and an SNR estimate good to ~0.02 dB, at half
|
||||
* the cost. The whole window is still captured and still >1 field -- we just don't need
|
||||
* all of it to measure. */
|
||||
#define NSYM_USE 140000
|
||||
|
||||
#define EYE_NSUB 65 /* 1430 % 65 == 0 -> phase step 22 */
|
||||
#define EYE_STEP (SYM_NUM / EYE_NSUB) /* = 22 */
|
||||
#define EYE_COLS (2 * EYE_NSUB) /* 130, spanning 2 symbol periods */
|
||||
#define EYE_ROWS 192 /* amplitude [-9,+9] */
|
||||
#define EYE_AMP 9.0f
|
||||
#define EYE_TRACE 256
|
||||
|
||||
#define SEG_LEN 832 /* symbols per data segment */
|
||||
|
||||
/*
|
||||
* The ORx RF AGC (dpd_rx_rfagc_1x) re-decides its gain index every 2048 samples at
|
||||
* 40 MSPS = 51.2 us, in 0.43 dB steps. Measured on a real window that is 3.24 % rms of
|
||||
* multiplicative gain jitter, which alone caps MER at 29.5 dB -- while the additive
|
||||
* noise alone would allow 33.5 dB. It is a receiver artifact, not transmitter
|
||||
* distortion (the shoulder is a clean -58 dB), and every real ATSC receiver normalises
|
||||
* it away with its own AGC. So track it out before measuring.
|
||||
*
|
||||
* Fingerprint: sigma(level) fits sigma_a^2 + (L + 1.25)^2 * sigma_g^2 -- its minimum
|
||||
* sits at L = -1.25, i.e. where symbol + pilot passes through zero. Additive noise and
|
||||
* timing jitter both give a level-INDEPENDENT sigma.
|
||||
*
|
||||
* GT_BLK must be well inside one AGC step (551 symbols); 64 symbols = 5.9 us costs only
|
||||
* 0.07 dB of over-fit (verified against a synthetic AWGN control).
|
||||
*/
|
||||
#define GT_BLK 64
|
||||
#define PILOT_DC 1.25f
|
||||
|
||||
/* ---- working storage (BSS; the app already runs at ~143 MB RSS) ---- */
|
||||
static float xi[NSAMP], xq[NSAMP]; /* window as float, 2 MB */
|
||||
static float ci[NSYM_MAX], cq[NSYM_MAX]; /* derotated symbols, 2.26 MB */
|
||||
static float gtrk[NSYM_MAX / GT_BLK + 2];
|
||||
static float bank[SYM_DEN][PSI_TAPS]; /* 216 KB, rebuilt per tau0 */
|
||||
static short bshift[SYM_DEN];
|
||||
static int hist[EYE_COLS][EYE_ROWS];
|
||||
|
||||
static const float JR[4] = {1.0f, 0.0f, -1.0f, 0.0f}; /* Re(j^k) */
|
||||
static const float JI[4] = {0.0f, 1.0f, 0.0f, -1.0f}; /* Im(j^k) */
|
||||
|
||||
/* ---- newest SNR, published to lcd_task.c ---- */
|
||||
static pthread_mutex_t snr_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static float snr_db_pub;
|
||||
static time_t snr_stamp;
|
||||
|
||||
int iq_get_snr(float *snr_db)
|
||||
{
|
||||
int fresh;
|
||||
if (!iq_spec_get_enable()) return 0;
|
||||
pthread_mutex_lock(&snr_mtx);
|
||||
fresh = snr_stamp && (time(NULL) - snr_stamp) <= IQ_SNR_MAX_AGE;
|
||||
if (fresh) *snr_db = snr_db_pub;
|
||||
pthread_mutex_unlock(&snr_mtx);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
void iq_vsb_clear_results(void)
|
||||
{
|
||||
pthread_mutex_lock(&snr_mtx);
|
||||
snr_stamp = 0;
|
||||
pthread_mutex_unlock(&snr_mtx);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ kernel */
|
||||
static float rrc_f(float t) /* t in units of the RRC's own symbol period */
|
||||
{
|
||||
float b = PSI_BETA, at = fabsf(t), num, den, s;
|
||||
if (at < 1e-6f)
|
||||
return 1.0f + b * (4.0f / (float)M_PI - 1.0f);
|
||||
if (fabsf(4.0f * b * at - 1.0f) < 1e-4f) {
|
||||
s = (float)M_PI / (4.0f * b);
|
||||
return (b / sqrtf(2.0f)) * ((1.0f + 2.0f / (float)M_PI) * sinf(s) +
|
||||
(1.0f - 2.0f / (float)M_PI) * cosf(s));
|
||||
}
|
||||
num = sinf((float)M_PI * t * (1.0f - b)) + 4.0f * b * t * cosf((float)M_PI * t * (1.0f + b));
|
||||
den = (float)M_PI * t * (1.0f - (4.0f * b * t) * (4.0f * b * t));
|
||||
return num / den;
|
||||
}
|
||||
|
||||
/* psi: the channel-centred pulse. Its "symbol period" is 2T, hence the /2.
|
||||
* Do NOT taper this with a window -- that destroys psi's Nyquist property and costs
|
||||
* 10..15 dB of floor (measured with Kaiser 4/6/8). Plain truncation is optimal. */
|
||||
static float psi_f(float u_in_T) { return rrc_f(0.5f * u_in_T); }
|
||||
|
||||
/*
|
||||
* The bank is rebuilt for every candidate tau0, i.e. ~50 times per window. Calling
|
||||
* psi_f() 1539*36 times per rebuild means ~1e6 libm sinf/cosf calls per window, which
|
||||
* cost 7.6 s on the A7. Tabulate psi once instead and interpolate: the kernel argument
|
||||
* (mu - mm)/sps stays inside +-20 symbol periods, and psi is band-limited to
|
||||
* 0.279 cycles/T, so a 1e-3 grid interpolates to ~4e-7.
|
||||
*/
|
||||
#define PT_STEP 0.001f
|
||||
#define PT_HALF 20.5f
|
||||
#define PT_N 41002 /* 2*20.5/0.001 + 2, 164 KB */
|
||||
static float psitab[PT_N];
|
||||
static int psitab_ready;
|
||||
|
||||
static void psi_table_init(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PT_N; i++)
|
||||
psitab[i] = psi_f(-PT_HALF + PT_STEP * (float)i);
|
||||
psitab_ready = 1;
|
||||
}
|
||||
|
||||
static float psi_lut(float u)
|
||||
{
|
||||
float f = (u + PT_HALF) / PT_STEP;
|
||||
int i = (int)f;
|
||||
float g;
|
||||
if (i < 0 || i >= PT_N - 1) return 0.0f;
|
||||
g = f - (float)i;
|
||||
return psitab[i] + g * (psitab[i + 1] - psitab[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* The bank only ever needs to exist for tau0 = 0.
|
||||
*
|
||||
* Restricting tau0 to q/1539 turns it into an integer offset of the phase index:
|
||||
* symbol k sits at sample (k*1430 + q)/1539, so p = (k*1430+q) mod 1539 and the
|
||||
* kernel for phase p is the same one regardless of q. The quantisation is
|
||||
* 1/1539 = 6.5e-4 sample, already finer than the 1e-3 the 45 dB floor demands.
|
||||
*
|
||||
* This matters: rebuilding the bank for every candidate tau0 cost 3.3 s per window
|
||||
* (49 rebuilds x 55404 kernel evaluations) and dominated everything else.
|
||||
*/
|
||||
static void build_bank(void)
|
||||
{
|
||||
const float inv_sps = 1539.0f / 1430.0f;
|
||||
int p, m;
|
||||
if (!psitab_ready) psi_table_init();
|
||||
for (p = 0; p < SYM_DEN; p++) {
|
||||
float mu = (float)p / (float)SYM_DEN;
|
||||
bshift[p] = 0;
|
||||
for (m = 0; m < PSI_TAPS; m++)
|
||||
bank[p][m] = psi_lut((mu - (float)(m - PSI_HALF)) * inv_sps);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- resample + derotate */
|
||||
/* c_k = y_k * j^k for k in [k0, k0+nsym), with tau0 = q/1539.
|
||||
* Returns 0 if the window is too short. */
|
||||
static int resample_syms(int k0, int nsym, int q)
|
||||
{
|
||||
int k, num, n;
|
||||
/* exact integer recurrence: sample position of symbol k is (k*1430 + q)/1539 */
|
||||
long long t = (long long)k0 * SYM_NUM + q;
|
||||
n = (int)(t / SYM_DEN);
|
||||
num = (int)(t % SYM_DEN);
|
||||
|
||||
for (k = 0; k < nsym; k++) {
|
||||
const float *h = bank[num];
|
||||
int base = n + bshift[num] - PSI_HALF;
|
||||
float yi = 0.0f, yq = 0.0f;
|
||||
int m, kk;
|
||||
|
||||
if (base < 0 || base + PSI_TAPS > NSAMP) return 0;
|
||||
/* Four independent accumulators. A single chain of `yi += h[m]*x[m]` is
|
||||
* latency-bound: every VFP fmla waits on the previous one (~8 cycles), which
|
||||
* is what made the demod take 1.8 s per window on the A7. PSI_TAPS is 36 = 4*9. */
|
||||
{ const float *pi = xi + base, *pq = xq + base;
|
||||
float i0 = 0, i1 = 0, i2 = 0, i3 = 0, q0 = 0, q1 = 0, q2 = 0, q3 = 0;
|
||||
for (m = 0; m < PSI_TAPS; m += 4) {
|
||||
i0 += h[m + 0] * pi[m + 0]; q0 += h[m + 0] * pq[m + 0];
|
||||
i1 += h[m + 1] * pi[m + 1]; q1 += h[m + 1] * pq[m + 1];
|
||||
i2 += h[m + 2] * pi[m + 2]; q2 += h[m + 2] * pq[m + 2];
|
||||
i3 += h[m + 3] * pi[m + 3]; q3 += h[m + 3] * pq[m + 3];
|
||||
}
|
||||
yi = (i0 + i1) + (i2 + i3);
|
||||
yq = (q0 + q1) + (q2 + q3);
|
||||
}
|
||||
kk = (k0 + k) & 3;
|
||||
ci[k] = yi * JR[kk] - yq * JI[kk];
|
||||
cq[k] = yi * JI[kk] + yq * JR[kk];
|
||||
|
||||
num += SYM_NUM;
|
||||
if (num >= SYM_DEN) { num -= SYM_DEN; n++; }
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- slicer */
|
||||
/* r[] is overwritten with the normalised statistic; returns SNR in dB. */
|
||||
static float slice_snr(float *r, int n, float *dc_out, float *scale_out)
|
||||
{
|
||||
double sum = 0.0, sd = 0.0, sdd = 0.0, se = 0.0, sud;
|
||||
float dc, scale, u, d;
|
||||
int i, it;
|
||||
|
||||
for (i = 0; i < n; i++) sum += r[i];
|
||||
dc = (float)(sum / n);
|
||||
|
||||
sum = 0.0;
|
||||
for (i = 0; i < n; i++) { u = r[i] - dc; sum += (double)u * u; }
|
||||
scale = sqrtf((float)(sum / n) / 21.0f); /* ideal mean(d^2) = 21 */
|
||||
if (!(scale > 0.0f)) return -99.0f;
|
||||
|
||||
for (it = 0; it < 2; it++) { /* two LS iterations converge */
|
||||
float inv = 1.0f / scale;
|
||||
sud = 0.0; sdd = 0.0;
|
||||
for (i = 0; i < n; i++) {
|
||||
u = r[i] - dc;
|
||||
d = 2.0f * floorf((u * inv - 1.0f) * 0.5f + 0.5f) + 1.0f;
|
||||
if (d > 7.0f) d = 7.0f;
|
||||
if (d < -7.0f) d = -7.0f;
|
||||
sud += (double)u * d; sdd += (double)d * d;
|
||||
}
|
||||
if (sdd <= 0.0) return -99.0f;
|
||||
scale = (float)(sud / sdd);
|
||||
}
|
||||
|
||||
sd = 0.0; se = 0.0;
|
||||
{ float inv = 1.0f / scale;
|
||||
for (i = 0; i < n; i++) {
|
||||
float rr = (r[i] - dc) * inv;
|
||||
d = 2.0f * floorf((rr - 1.0f) * 0.5f + 0.5f) + 1.0f;
|
||||
if (d > 7.0f) d = 7.0f;
|
||||
if (d < -7.0f) d = -7.0f;
|
||||
sd += (double)d * d;
|
||||
se += (double)(rr - d) * (rr - d);
|
||||
r[i] = rr; /* keep the normalised statistic */
|
||||
}}
|
||||
if (se <= 0.0) return 99.0f;
|
||||
if (dc_out) *dc_out = dc;
|
||||
if (scale_out) *scale_out = scale;
|
||||
return 10.0f * log10f((float)(sd / se));
|
||||
}
|
||||
|
||||
static float slice1(float r)
|
||||
{
|
||||
float d = 2.0f * floorf((r - 1.0f) * 0.5f + 0.5f) + 1.0f;
|
||||
if (d > 7.0f) d = 7.0f;
|
||||
if (d < -7.0f) d = -7.0f;
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decision-directed gain tracking. r[] holds the normalised statistic; the AGC scales
|
||||
* the whole signal, pilot included, hence the +1.25 on both sides of the LS fit.
|
||||
* Blocks are linearly interpolated between their centres so the correction has no
|
||||
* step at a block edge. Returns the rms gain deviation (a useful ORx-AGC diagnostic).
|
||||
*/
|
||||
static float gain_track(float *r, int n)
|
||||
{
|
||||
int nb = n / GT_BLK, b, i;
|
||||
double m = 0.0, v = 0.0;
|
||||
|
||||
if (nb < 3) return 0.0f;
|
||||
for (b = 0; b < nb; b++) {
|
||||
double num = 0.0, den = 0.0;
|
||||
for (i = b * GT_BLK; i < (b + 1) * GT_BLK; i++) {
|
||||
float d = slice1(r[i]) + PILOT_DC;
|
||||
num += (double)(r[i] + PILOT_DC) * d;
|
||||
den += (double)d * d;
|
||||
}
|
||||
gtrk[b] = (den > 0.0) ? (float)(num / den) : 1.0f;
|
||||
m += gtrk[b]; v += (double)gtrk[b] * gtrk[b];
|
||||
}
|
||||
m /= nb; v = v / nb - m * m;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
float pos = (float)i / GT_BLK - 0.5f;
|
||||
int b0 = (int)floorf(pos);
|
||||
float f = pos - (float)b0, g;
|
||||
if (b0 < 0) { b0 = 0; f = 0.0f; }
|
||||
if (b0 >= nb - 1) { b0 = nb - 2; f = 1.0f; }
|
||||
g = gtrk[b0] + f * (gtrk[b0 + 1] - gtrk[b0]);
|
||||
r[i] = (g > 0.1f) ? (r[i] + PILOT_DC) / g - PILOT_DC : r[i];
|
||||
}
|
||||
return (v > 0.0) ? (float)sqrt(v) : 0.0f;
|
||||
}
|
||||
|
||||
static float theta_of(int nsym)
|
||||
{
|
||||
double si = 0.0, sq = 0.0;
|
||||
int i;
|
||||
for (i = 0; i < nsym; i++) { si += ci[i]; sq += cq[i]; }
|
||||
return atan2f((float)sq, (float)si);
|
||||
}
|
||||
|
||||
/* de-rotate in place: ci <- Re{c e^-jtheta}, cq <- Im{...} */
|
||||
static void apply_theta(int nsym, float th)
|
||||
{
|
||||
float c = cosf(th), s = sinf(th);
|
||||
int i;
|
||||
for (i = 0; i < nsym; i++) {
|
||||
float a = ci[i] * c + cq[i] * s;
|
||||
float b = cq[i] * c - ci[i] * s;
|
||||
ci[i] = a; cq[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
/* SNR at one candidate phase offset q, on a probe block. No bank rebuild. */
|
||||
static float probe(int q, int k0, int nsym)
|
||||
{
|
||||
q %= SYM_DEN;
|
||||
if (q < 0) q += SYM_DEN;
|
||||
if (!resample_syms(k0, nsym, q)) return -99.0f;
|
||||
apply_theta(nsym, theta_of(nsym));
|
||||
return slice_snr(ci, nsym, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* tau0 needs |error| < 1e-3 sample to keep the 45 dB floor (3e-3 -> 42.8 dB,
|
||||
* 1e-2 -> 34.4 dB). A 1/32 grid plus a parabola lands an order of magnitude short,
|
||||
* so refine on a 1/256 grid.
|
||||
*
|
||||
* *** The search must run from scratch on every window. *** tau0 is constant in
|
||||
* absolute time, but each window starts wherever ram2_iq_ctrl happened to trigger,
|
||||
* and that instant is not locked to the symbol clock -- so sample 0 of every window
|
||||
* has a different symbol phase. Warm-starting from the previous window pins the
|
||||
* search to a stale tau0 and the SNR collapses from 28 dB to 15 dB (measured).
|
||||
*/
|
||||
static int find_tau(void)
|
||||
{
|
||||
const int K0 = 40000;
|
||||
/* {step, half-width, probe symbols}: sweep the whole period, then two zooms.
|
||||
* Each stage rescans its own neighbourhood from scratch, so the SNR estimates
|
||||
* being compared always come from the same block length. */
|
||||
static const int stage[3][3] = { {48, 0, 512}, {6, 48, 1024}, {1, 6, 4096} };
|
||||
int best = 0, st;
|
||||
|
||||
for (st = 0; st < 3; st++) {
|
||||
int step = stage[st][0], half = stage[st][1], np = stage[st][2];
|
||||
int lo = (st == 0) ? 0 : best - half;
|
||||
int hi = (st == 0) ? SYM_DEN - 1 : best + half;
|
||||
float bs = -1e30f;
|
||||
int q, b = best;
|
||||
for (q = lo; q <= hi; q += step) {
|
||||
float s = probe(q, K0, np);
|
||||
if (s > bs) { bs = s; b = q; }
|
||||
}
|
||||
best = b;
|
||||
}
|
||||
best %= SYM_DEN;
|
||||
if (best < 0) best += SYM_DEN;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------- segment sync check */
|
||||
/* Every data segment starts with [+5,-5,-5,+5]; period 832. Correlating the slicer
|
||||
* output against it validates timing, polarity and gain in one shot. */
|
||||
static float seg_sync(const float *r, int nsym, int *off_out)
|
||||
{
|
||||
static const float pat[4] = {5.0f, -5.0f, -5.0f, 5.0f};
|
||||
int nseg = (nsym - 4) / SEG_LEN, off, s, best = 0;
|
||||
double sc, peak = 0.0, sumsq = 0.0;
|
||||
double *score = (double *)malloc(sizeof(double) * SEG_LEN);
|
||||
float ratio;
|
||||
|
||||
if (!score || nseg < 8) { free(score); return 0.0f; }
|
||||
for (off = 0; off < SEG_LEN - 3; off++) {
|
||||
sc = 0.0;
|
||||
for (s = 0; s < nseg; s++) {
|
||||
const float *p = r + s * SEG_LEN + off;
|
||||
sc += p[0] * pat[0] + p[1] * pat[1] + p[2] * pat[2] + p[3] * pat[3];
|
||||
}
|
||||
score[off] = sc / nseg;
|
||||
if (fabs(score[off]) > fabs(peak)) { peak = score[off]; best = off; }
|
||||
}
|
||||
for (off = 0; off < SEG_LEN - 3; off++)
|
||||
if (off != best) sumsq += score[off] * score[off];
|
||||
free(score);
|
||||
ratio = (float)(fabs(peak) / sqrt(sumsq / (SEG_LEN - 4)));
|
||||
if (off_out) *off_out = best;
|
||||
return ratio;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- eye */
|
||||
static void build_eye(int q, float th, float dc, float scale, int k0, int nsym)
|
||||
{
|
||||
float wr[EYE_COLS], wi[EYE_COLS];
|
||||
float ct = cosf(th), st = sinf(th), inv = 1.0f / scale;
|
||||
int i, j, k, nb = nsym / GT_BLK;
|
||||
|
||||
memset(hist, 0, sizeof(hist));
|
||||
/* fp = Rs/4 -> the carrier advances pi/2 per symbol; per sub-sample column that is
|
||||
* pi/2 * (j-65)/65. The integer part j^k is folded in below. */
|
||||
for (j = 0; j < EYE_COLS; j++) {
|
||||
float a = (float)M_PI * 0.5f * ((float)(j - EYE_NSUB) / (float)EYE_NSUB);
|
||||
wr[j] = cosf(a); wi[j] = sinf(a);
|
||||
}
|
||||
|
||||
for (i = 0; i < EYE_TRACE; i++) {
|
||||
/* Phase recurrence instead of a 64-bit div/mod per point: the first column of
|
||||
* trace i sits at P = k*1430 + q - 65*22 phase units, each column steps by 22. */
|
||||
long long P;
|
||||
int n, p;
|
||||
|
||||
/* stay inside [k0, k0+nsym): the gain track is only defined there */
|
||||
k = k0 + 1000 + (int)((long long)i * (nsym - 2000) / EYE_TRACE);
|
||||
P = (long long)k * SYM_NUM + q - (long long)EYE_NSUB * EYE_STEP;
|
||||
n = (int)(P / SYM_DEN); p = (int)(P % SYM_DEN);
|
||||
if (p < 0) { p += SYM_DEN; n--; }
|
||||
|
||||
for (j = 0; j < EYE_COLS; j++) {
|
||||
const float *h = bank[p];
|
||||
int base = n + bshift[p] - PSI_HALF;
|
||||
int m, kk = k & 3, row;
|
||||
float yi, yq, ri, rq, re_, im_, r;
|
||||
|
||||
if (base >= 0 && base + PSI_TAPS <= NSAMP) {
|
||||
const float *pi = xi + base, *pq = xq + base;
|
||||
float i0 = 0, i1 = 0, i2 = 0, i3 = 0, q0 = 0, q1 = 0, q2 = 0, q3 = 0;
|
||||
for (m = 0; m < PSI_TAPS; m += 4) {
|
||||
i0 += h[m + 0] * pi[m + 0]; q0 += h[m + 0] * pq[m + 0];
|
||||
i1 += h[m + 1] * pi[m + 1]; q1 += h[m + 1] * pq[m + 1];
|
||||
i2 += h[m + 2] * pi[m + 2]; q2 += h[m + 2] * pq[m + 2];
|
||||
i3 += h[m + 3] * pi[m + 3]; q3 += h[m + 3] * pq[m + 3];
|
||||
}
|
||||
yi = (i0 + i1) + (i2 + i3);
|
||||
yq = (q0 + q1) + (q2 + q3);
|
||||
ri = yi * JR[kk] - yq * JI[kk]; /* c = y * j^k */
|
||||
rq = yi * JI[kk] + yq * JR[kk];
|
||||
re_ = ri * wr[j] - rq * wi[j]; /* * e^{j pi/2 (j-65)/65} */
|
||||
im_ = rq * wr[j] + ri * wi[j];
|
||||
r = (re_ * ct + im_ * st - dc) * inv; /* Re{ ... * e^{-j theta} } */
|
||||
{ /* undo the ORx AGC gain step at this symbol, as for the SNR */
|
||||
float pos = (float)(k - k0) / GT_BLK - 0.5f;
|
||||
int b0 = (int)floorf(pos);
|
||||
float f = pos - (float)b0, g;
|
||||
if (b0 < 0) { b0 = 0; f = 0.0f; }
|
||||
if (b0 >= nb - 1) { b0 = nb - 2; f = 1.0f; }
|
||||
g = gtrk[b0] + f * (gtrk[b0 + 1] - gtrk[b0]);
|
||||
if (g > 0.1f) r = (r + PILOT_DC) / g - PILOT_DC;
|
||||
}
|
||||
|
||||
row = (int)((r + EYE_AMP) / (2.0f * EYE_AMP) * EYE_ROWS);
|
||||
if (row >= 0 && row < EYE_ROWS) hist[j][row]++;
|
||||
}
|
||||
p += EYE_STEP;
|
||||
if (p >= SYM_DEN) { p -= SYM_DEN; n++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- base64 */
|
||||
static const char B64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static int b64(const unsigned char *in, int n, char *out)
|
||||
{
|
||||
int i, o = 0;
|
||||
for (i = 0; i + 2 < n; i += 3) {
|
||||
unsigned v = (in[i] << 16) | (in[i + 1] << 8) | in[i + 2];
|
||||
out[o++] = B64[(v >> 18) & 63]; out[o++] = B64[(v >> 12) & 63];
|
||||
out[o++] = B64[(v >> 6) & 63]; out[o++] = B64[v & 63];
|
||||
}
|
||||
if (i < n) {
|
||||
unsigned v = in[i] << 16;
|
||||
int rem = n - i;
|
||||
if (rem == 2) v |= in[i + 1] << 8;
|
||||
out[o++] = B64[(v >> 18) & 63]; out[o++] = B64[(v >> 12) & 63];
|
||||
out[o++] = (rem == 2) ? B64[(v >> 6) & 63] : '=';
|
||||
out[o++] = '=';
|
||||
}
|
||||
out[o] = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
/* --------------------------------------------- level percentiles */
|
||||
#define LH_BINS 256
|
||||
#define LH_SPAN 1.0f /* each level cloud is binned over L +- 1.0 */
|
||||
|
||||
/* value at the `frac` quantile of a level cloud centred on `L` */
|
||||
static float lh_pct(const int *h, int cnt, float frac, float L)
|
||||
{
|
||||
int want = (int)(frac * cnt), acc = 0, b;
|
||||
for (b = 0; b < LH_BINS; b++) {
|
||||
acc += h[b];
|
||||
if (acc >= want)
|
||||
return L - LH_SPAN + (2.0f * LH_SPAN) * ((float)b + 0.5f) / LH_BINS;
|
||||
}
|
||||
return L + LH_SPAN;
|
||||
}
|
||||
|
||||
/* wall-clock helper for the per-phase timing printed at the end */
|
||||
static void now(struct timespec *t) { clock_gettime(CLOCK_MONOTONIC, t); }
|
||||
static int ms(struct timespec a, struct timespec b)
|
||||
{
|
||||
return (int)((b.tv_sec - a.tv_sec) * 1000 + (b.tv_nsec - a.tv_nsec) / 1000000);
|
||||
}
|
||||
|
||||
/* ============================================================= entry point */
|
||||
void iq_vsb_analyse(const unsigned char *win, int wid)
|
||||
{
|
||||
struct timespec t0, t1, t2, t3, t4, t5;
|
||||
static unsigned char png[EYE_COLS * EYE_ROWS];
|
||||
static char b64buf[(EYE_COLS * EYE_ROWS + 2) / 3 * 4 + 8];
|
||||
static char json[64 * 1024];
|
||||
|
||||
float th, dc, scale, snr, snr_raw, gjit = 0.0f, qi = 0.0f, coff, ratio, eye_w, minh, tau;
|
||||
int q;
|
||||
double e = 0.0, s1 = 0.0, lsum[8], lsq[8];
|
||||
int i, j, nsym, k0, off = 0, pos, sync, eye_open = 0, lcnt[8];
|
||||
float lev[8], sig[8], eyeh[7], lp01[8], lp99[8];
|
||||
|
||||
now(&t0);
|
||||
/* unpack once: big-endian int16 I,Q -> float */
|
||||
for (i = 0; i < NSAMP; i++) {
|
||||
const unsigned char *q = win + i * 4;
|
||||
xi[i] = (float)(short)((q[0] << 8) | q[1]);
|
||||
xq[i] = (float)(short)((q[2] << 8) | q[3]);
|
||||
e += (double)xi[i] * xi[i] + (double)xq[i] * xq[i];
|
||||
}
|
||||
/* a dead ORx link (0xBB=0x00 after a cold boot) hands us an all-zero window */
|
||||
if (e / NSAMP < 100.0) {
|
||||
FILE *f = fopen("/tmp/iq_eye.json.tmp", "w");
|
||||
if (f) { fprintf(f, "{\"wid\":%d,\"sync\":false,\"error\":\"no signal\"}\n", wid);
|
||||
fclose(f); rename("/tmp/iq_eye.json.tmp", "/tmp/iq_eye.json"); }
|
||||
return;
|
||||
}
|
||||
|
||||
now(&t1);
|
||||
build_bank(); /* once; tau0 is an integer phase offset, see above */
|
||||
q = find_tau(); /* every window: its start is not symbol-locked */
|
||||
tau = (float)q / (float)SYM_DEN;
|
||||
now(&t2);
|
||||
|
||||
k0 = (int)(GUARD / SPS);
|
||||
nsym = (int)((NSAMP - 2 * GUARD) / SPS) - 20;
|
||||
if (nsym > NSYM_USE) nsym = NSYM_USE;
|
||||
|
||||
if (!resample_syms(k0, nsym, q)) return;
|
||||
th = theta_of(nsym);
|
||||
apply_theta(nsym, th);
|
||||
|
||||
/* premise check: the pilot phase must not drift across the window */
|
||||
{ double a1 = 0, b1 = 0, a2 = 0, b2 = 0;
|
||||
for (i = 0; i < nsym / 2; i++) { a1 += ci[i]; b1 += cq[i]; }
|
||||
for (i = nsym / 2; i < nsym; i++) { a2 += ci[i]; b2 += cq[i]; }
|
||||
coff = (atan2f((float)b2, (float)a2) - atan2f((float)b1, (float)a1)) /
|
||||
(2.0f * (float)M_PI * ((float)(nsym / 2) / 10762237.762f));
|
||||
}
|
||||
now(&t3);
|
||||
snr_raw = slice_snr(ci, nsym, &dc, &scale); /* ci[] is now the normalised statistic */
|
||||
for (i = 0; i < nsym; i++) { float q = cq[i] / scale; s1 += (double)q * q; }
|
||||
qi = 10.0f * log10f((float)(21.0 * nsym / (s1 + 1e-9)));
|
||||
|
||||
/* Divide out the ORx AGC's gain steps, then re-measure. Everything downstream
|
||||
* (levels, sigma, eye height, eye diagram) uses the tracked signal. */
|
||||
gjit = gain_track(ci, nsym);
|
||||
{ double sd = 0.0, se = 0.0;
|
||||
for (i = 0; i < nsym; i++) {
|
||||
float d = slice1(ci[i]);
|
||||
sd += (double)d * d;
|
||||
se += (double)(ci[i] - d) * (ci[i] - d);
|
||||
}
|
||||
snr = (se > 0.0) ? 10.0f * log10f((float)(sd / se)) : 99.0f;
|
||||
}
|
||||
|
||||
ratio = seg_sync(ci, nsym, &off);
|
||||
sync = (ratio > 10.0f) && (snr > 5.0f);
|
||||
|
||||
/* Level statistics at the decision instant, straight from the symbol samples.
|
||||
* eye_h uses real 1%/99% percentiles, NOT lev +- 3*sigma: with a 3-sigma proxy the
|
||||
* "min(eye_h) ~= 2 - 6*sigma" cross-check (Task06-7 criterion 6b) becomes an
|
||||
* identity and stops being able to detect non-Gaussian distortion. */
|
||||
{ static int lh[8][LH_BINS];
|
||||
memset(lh, 0, sizeof(lh));
|
||||
for (j = 0; j < 8; j++) { lcnt[j] = 0; lsum[j] = 0.0; lsq[j] = 0.0; }
|
||||
for (i = 0; i < nsym; i++) {
|
||||
float v = ci[i];
|
||||
int j2 = (int)floorf((v + 8.0f) * 0.5f); /* level index from -7..7 */
|
||||
int b;
|
||||
if (j2 < 0 || j2 > 7) continue;
|
||||
if (fabsf(v - (float)(2 * j2 - 7)) >= LH_SPAN) continue;
|
||||
lsum[j2] += v; lsq[j2] += (double)v * v; lcnt[j2]++;
|
||||
b = (int)((v - (float)(2 * j2 - 7) + LH_SPAN) / (2.0f * LH_SPAN) * LH_BINS);
|
||||
if (b < 0) b = 0;
|
||||
if (b >= LH_BINS) b = LH_BINS - 1;
|
||||
lh[j2][b]++;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (lcnt[j] < 100) { lev[j] = (float)(2 * j - 7); sig[j] = 0.0f; continue; }
|
||||
lev[j] = (float)(lsum[j] / lcnt[j]);
|
||||
sig[j] = sqrtf((float)(lsq[j] / lcnt[j] - (double)lev[j] * lev[j]));
|
||||
lp01[j] = lh_pct(lh[j], lcnt[j], 0.01f, (float)(2 * j - 7));
|
||||
lp99[j] = lh_pct(lh[j], lcnt[j], 0.99f, (float)(2 * j - 7));
|
||||
}
|
||||
for (j = 0; j < 7; j++) eyeh[j] = lp01[j + 1] - lp99[j];
|
||||
}
|
||||
|
||||
now(&t4);
|
||||
build_eye(q, th, dc, scale, k0, nsym);
|
||||
now(&t5);
|
||||
|
||||
/* log-compress the persistence map */
|
||||
{ int mx = 1;
|
||||
for (j = 0; j < EYE_COLS; j++)
|
||||
for (i = 0; i < EYE_ROWS; i++) if (hist[j][i] > mx) mx = hist[j][i];
|
||||
for (j = 0; j < EYE_COLS; j++)
|
||||
for (i = 0; i < EYE_ROWS; i++)
|
||||
png[j * EYE_ROWS + i] = (unsigned char)
|
||||
(255.0f * logf(1.0f + hist[j][i]) / logf(1.0f + mx) + 0.5f);
|
||||
}
|
||||
b64(png, EYE_COLS * EYE_ROWS, b64buf);
|
||||
|
||||
/* Eye width: how many columns keep the central eye (the band between the -1 and +1
|
||||
* clouds) essentially empty. Two traps:
|
||||
* - lp99[3] >= lp01[4] means the clouds already touch: the eye is shut, width 0,
|
||||
* NOT "every column clear" (which is what an empty row loop would report);
|
||||
* - the band is bounded by 1%/99% percentiles, so ~1% of each cloud lies inside it
|
||||
* by construction. Demanding an exactly empty band gives 0 columns always.
|
||||
* Call a column open when < 0.5% of its samples fall in the band. */
|
||||
{ float lo = lp99[3], hi = lp01[4];
|
||||
if (hi > lo) {
|
||||
int r0 = (int)((lo + EYE_AMP) / (2 * EYE_AMP) * EYE_ROWS) + 1;
|
||||
int r1 = (int)((hi + EYE_AMP) / (2 * EYE_AMP) * EYE_ROWS) - 1;
|
||||
if (r0 < 0) r0 = 0;
|
||||
if (r1 >= EYE_ROWS) r1 = EYE_ROWS - 1;
|
||||
if (r1 >= r0) { /* a band narrower than one row means shut */
|
||||
for (j = 0; j < EYE_COLS; j++) {
|
||||
int inband = 0;
|
||||
for (i = r0; i <= r1; i++) inband += hist[j][i];
|
||||
if (inband * 200 <= EYE_TRACE) eye_open++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eye_w = (float)eye_open * 2.0f / (float)EYE_COLS; /* in UI */
|
||||
|
||||
pos = snprintf(json, sizeof(json),
|
||||
"{\"ts\":%ld,\"wid\":%d,\"nsym\":%d,\"sync\":%s,"
|
||||
"\"snr_db\":%.2f,\"snr_raw_db\":%.2f,\"gain_jitter_pct\":%.2f,"
|
||||
"\"q_isi_db\":%.2f,\"tau\":%.4f,\"theta_deg\":%.2f,"
|
||||
"\"carrier_off_hz\":%.3f,\"segsync_ratio\":%.1f,\"segsync_off\":%d,"
|
||||
"\"levels\":[%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f],"
|
||||
"\"sigma\":[%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f],"
|
||||
"\"eye_h\":[%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f],\"eye_w_ui\":%.3f,"
|
||||
"\"eye\":{\"cols\":%d,\"rows\":%d,\"ui\":2.0,\"amp\":%.1f,\"log\":true,\"data\":\"%s\"}}\n",
|
||||
(long)time(NULL), wid, nsym, sync ? "true" : "false",
|
||||
snr, snr_raw, 100.0f * gjit, qi, tau, th * 180.0f / (float)M_PI, coff, ratio, off,
|
||||
lev[0], lev[1], lev[2], lev[3], lev[4], lev[5], lev[6], lev[7],
|
||||
sig[0], sig[1], sig[2], sig[3], sig[4], sig[5], sig[6], sig[7],
|
||||
eyeh[0], eyeh[1], eyeh[2], eyeh[3], eyeh[4], eyeh[5], eyeh[6], eye_w,
|
||||
EYE_COLS, EYE_ROWS, EYE_AMP, b64buf);
|
||||
|
||||
{ FILE *f = fopen("/tmp/iq_eye.json.tmp", "w");
|
||||
if (f) { fwrite(json, 1, pos, f); fclose(f);
|
||||
rename("/tmp/iq_eye.json.tmp", "/tmp/iq_eye.json"); }
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
pthread_mutex_lock(&snr_mtx);
|
||||
snr_db_pub = snr; snr_stamp = time(NULL);
|
||||
pthread_mutex_unlock(&snr_mtx);
|
||||
}
|
||||
|
||||
minh = eyeh[0];
|
||||
for (j = 1; j < 7; j++) if (eyeh[j] < minh) minh = eyeh[j];
|
||||
printf("[iq_vsb] win %d: SNR %.2f dB (raw %.2f, ORx AGC jitter %.2f%%) tau %.4f theta %+.1f deg coff %+.3f Hz "
|
||||
"segsync %.1f@%d eye_w %.3f UI min_eye_h %.2f %s "
|
||||
"[ms: unpack %d tau %d demod %d stats %d eye %d total %d]\n",
|
||||
wid, snr, snr_raw, 100.0f * gjit, tau, th * 180.0f / (float)M_PI, coff, ratio, off, eye_w,
|
||||
minh, sync ? "SYNC" : "NOSYNC",
|
||||
ms(t0, t1), ms(t1, t2), ms(t2, t3), ms(t3, t4), ms(t4, t5), ms(t0, t5));
|
||||
}
|
||||
Executable
+2352
File diff suppressed because it is too large
Load Diff
Executable
+2436
File diff suppressed because it is too large
Load Diff
Executable
+15126
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,619 @@
|
||||
|
||||
/*
|
||||
@NOT_ACT_USED
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
版权所有 (C), 2001-2011, 上海全波通信技术有限公司
|
||||
|
||||
******************************************************************************
|
||||
文 件 名 : log_task.c
|
||||
版 本 号 : 初稿
|
||||
作 者 : 郭金涛
|
||||
生成日期 : 2014年1月16日
|
||||
最近修改 :
|
||||
功能描述 : 系统日志处理文件,系统日志放在第2片E2中. 除了部分备份参数,大部分还未使用
|
||||
函数列表 :
|
||||
log_task
|
||||
修改历史 :
|
||||
1.日 期 : 2014年1月16日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 创建文件
|
||||
|
||||
******************************************************************************/
|
||||
#include <string.h>
|
||||
#include "rtc.h"
|
||||
#include "type.h"
|
||||
#include "delay.h"
|
||||
#include "os_task.h"
|
||||
#include "sys_config.h"
|
||||
#include "eeprom.h"
|
||||
#include "i2c_drv.h"
|
||||
#include "log_task.h"
|
||||
|
||||
|
||||
#if USE_LOG_MODULE
|
||||
#if (LOG_MAX_RECORD_NUM*LOG_PER_RECORD_SIZE+3)>3900
|
||||
#error "sys log max size must < 3900 bytes"
|
||||
#endif
|
||||
|
||||
extern void* rtc_get_log_mem_address(void);
|
||||
|
||||
|
||||
#define LOG_USE_RAM_FLAG 0X4329
|
||||
#define LOG_USE_E2PROM_FLAG ((uint8)LOG_USE_RAM_FLAG) //每个平台要区分开,平台切换后,日志需初始化
|
||||
|
||||
|
||||
|
||||
static S_OS_LOG *pos_log;
|
||||
static uint32 log_use_bk_ram_flag = 0; //是否使用bkram标志, 若使用,则存储时先把日志放入RAM,否则直接存入E2中
|
||||
static uint32 log_e2_latest_index = 0; //未使用BKRAM时有效
|
||||
static uint32 log_e2_num = 0;
|
||||
|
||||
static uint8 log_save_bit_map[13]; //LOG_MAX_RECORD_NUM/8+1 13字节 每位表示一条日志是否需要存E2ROM
|
||||
|
||||
#define LOG_SET_ALL_SAVE_BIT() \
|
||||
do{memset(log_save_bit_map,0xff,sizeof(log_save_bit_map));}while(0)
|
||||
|
||||
#define LOG_SET_SAVE_BIT_INDEX(n) \
|
||||
do{ \
|
||||
uint32 LOG_T_N = (n)/8; \
|
||||
uint32 LOT_T_O = (n)%8; \
|
||||
log_save_bit_map[LOG_T_N]|=(1<<LOT_T_O);\
|
||||
}while(0)
|
||||
#define LOG_CLEAR_SAVE_BIT_INDEX(n) \
|
||||
do{ \
|
||||
uint32 LOG_T_N = (n)/8; \
|
||||
uint32 LOT_T_O = (n)%8; \
|
||||
log_save_bit_map[LOG_T_N]&=~(1<<LOT_T_O);\
|
||||
}while(0)
|
||||
|
||||
#define LOG_SAVE_BIT_IS_SET(index) (log_save_bit_map[(index)/8]&(1<<((index)%8)))
|
||||
|
||||
|
||||
|
||||
//上电后,若RAM中为无效数据,从E2中更新数据
|
||||
static void log_init_ram_by_e2prom(S_OS_LOG *plog)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint32 address = 0;
|
||||
S_LOG_STRUCT log_temp[2]; //64字节,E2的一页
|
||||
|
||||
//判断E2中的有效标志是否置位
|
||||
if(c256_byteread2(E2_SYSTEM_LOG_VALID_ADDRESS)!=LOG_USE_E2PROM_FLAG)
|
||||
{
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_VALID_ADDRESS,LOG_USE_E2PROM_FLAG);
|
||||
|
||||
LOG_SET_ALL_SAVE_BIT();
|
||||
plog->lastest_index = 0;
|
||||
plog->total_num = 0;
|
||||
memset(plog->log,0,sizeof(plog->log));
|
||||
return;
|
||||
}
|
||||
|
||||
plog->lastest_index = c256_byteread2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS);
|
||||
plog->total_num = c256_byteread2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS);
|
||||
if(plog->lastest_index>LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
plog->lastest_index = 0;
|
||||
}
|
||||
if(plog->total_num>LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
plog->total_num = LOG_MAX_RECORD_NUM;
|
||||
}
|
||||
|
||||
//一次读取两条log
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS;
|
||||
for(i=0;i<LOG_MAX_RECORD_NUM/2;i++,address+=LOG_PER_RECORD_SIZE*2)
|
||||
{
|
||||
atmel_read_e2((uint8*)&log_temp,address,LOG_PER_RECORD_SIZE*2);
|
||||
memcpy(&plog->log[i*2],log_temp,LOG_PER_RECORD_SIZE*2);
|
||||
}
|
||||
|
||||
//判断读取的log是否有效
|
||||
for(i=0;i<LOG_MAX_RECORD_NUM;i++)
|
||||
{
|
||||
if(plog->log[i].valid!=1)
|
||||
{
|
||||
LOG_SET_SAVE_BIT_INDEX(i); //同时更新E2PROM
|
||||
memset(&plog->log[i],0,sizeof(S_LOG_STRUCT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//上电检查E2PROM中是否和RAM中的一致,以RAM有效,则以RAM为准
|
||||
static void log_init_e2prom_by_ram(S_OS_LOG *plog)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint32 address = 0;
|
||||
S_LOG_STRUCT log_temp;
|
||||
|
||||
//判断E2中的有效标志是否置位,若未置为,则E2需要全部更新
|
||||
if(c256_byteread2(E2_SYSTEM_LOG_VALID_ADDRESS)!=LOG_USE_E2PROM_FLAG)
|
||||
{
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_VALID_ADDRESS,LOG_USE_E2PROM_FLAG);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS,plog->lastest_index);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS,plog->total_num);
|
||||
LOG_SET_ALL_SAVE_BIT();
|
||||
return;
|
||||
}
|
||||
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS;
|
||||
for(i=0;i<LOG_MAX_RECORD_NUM;i++,address+=LOG_PER_RECORD_SIZE)
|
||||
{
|
||||
atmel_read_e2((uint8*)&log_temp,address,LOG_PER_RECORD_SIZE);
|
||||
if(memcmp(&plog->log[i],&log_temp,LOG_PER_RECORD_SIZE))
|
||||
{
|
||||
LOG_SET_SAVE_BIT_INDEX(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void log_save_new_record(MSG *pmsg)
|
||||
{
|
||||
S_LOG_STRUCT *plog;
|
||||
uint32 address;
|
||||
|
||||
if(!pmsg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(pmsg->wPara==LOG_TYPE_INVALID)
|
||||
{
|
||||
if(pmsg->lPara)
|
||||
{
|
||||
free_mem((void*)pmsg->lPara);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
plog = (S_LOG_STRUCT*)pmsg->lPara;
|
||||
if(log_use_bk_ram_flag)
|
||||
{
|
||||
if(pos_log->total_num+1<LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
pos_log->total_num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos_log->total_num = LOG_MAX_RECORD_NUM;
|
||||
}
|
||||
memcpy(&pos_log->log[pos_log->lastest_index],plog,LOG_PER_RECORD_SIZE);
|
||||
LOG_SET_SAVE_BIT_INDEX(pos_log->lastest_index);
|
||||
pos_log->log[pos_log->lastest_index].valid = 1;
|
||||
|
||||
if(pos_log->lastest_index+1<LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
pos_log->lastest_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos_log->lastest_index = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(log_e2_num+1<LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
log_e2_num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e2_num = LOG_MAX_RECORD_NUM;
|
||||
}
|
||||
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS, log_e2_latest_index);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS, log_e2_num);
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS+log_e2_latest_index*LOG_PER_RECORD_SIZE;
|
||||
|
||||
plog->valid = 1;
|
||||
atmel_write_e2((uint8*)plog,address,LOG_PER_RECORD_SIZE);
|
||||
if(log_e2_latest_index+1<LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
log_e2_latest_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e2_latest_index = 0;
|
||||
}
|
||||
}
|
||||
if(pmsg->lPara)
|
||||
{
|
||||
free_mem((void*)pmsg->lPara);
|
||||
}
|
||||
}
|
||||
static void log_init_mem_para(void)
|
||||
{
|
||||
pos_log =(S_OS_LOG*)rtc_get_log_mem_address();
|
||||
if(pos_log)
|
||||
{
|
||||
log_use_bk_ram_flag = 1;
|
||||
if(pos_log->ram_flag!=LOG_USE_RAM_FLAG)
|
||||
{
|
||||
pos_log->ram_flag=LOG_USE_RAM_FLAG;
|
||||
log_init_ram_by_e2prom(pos_log);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_init_e2prom_by_ram(pos_log);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_use_bk_ram_flag = 0;
|
||||
if(c256_byteread2(E2_SYSTEM_LOG_VALID_ADDRESS)!=LOG_USE_E2PROM_FLAG)
|
||||
{
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_VALID_ADDRESS,LOG_USE_E2PROM_FLAG);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS,0);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS,0);
|
||||
log_e2_latest_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e2_latest_index = c256_byteread2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS);
|
||||
log_e2_num = c256_byteread2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS);
|
||||
if(log_e2_latest_index>LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
log_e2_latest_index = 0;
|
||||
log_e2_num = 0;
|
||||
}
|
||||
if(log_e2_num>LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
log_e2_num = LOG_MAX_RECORD_NUM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//周期性检查是否有LOG需要存E2PROM
|
||||
static void log_check_save_to_e2prom(void)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint32 j = 0;
|
||||
S_LOG_STRUCT *ponelog;
|
||||
uint32 address;
|
||||
|
||||
//已经直接存入E2PROM
|
||||
if(!log_use_bk_ram_flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ponelog = &pos_log->log[0];
|
||||
for(i=0;i<sizeof(log_save_bit_map);i++)
|
||||
{
|
||||
if(log_save_bit_map[i]==0)
|
||||
{
|
||||
ponelog+=8;
|
||||
continue;
|
||||
}
|
||||
for(j=0;j<8;j++,ponelog++)
|
||||
{
|
||||
if(LOG_SAVE_BIT_IS_SET(i*8+j))
|
||||
{
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS+(i*8+j)*LOG_PER_RECORD_SIZE;
|
||||
|
||||
atmel_write_e2((uint8*)ponelog,address,LOG_PER_RECORD_SIZE);
|
||||
LOG_CLEAR_SAVE_BIT_INDEX(i*8+j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void log_task(void * pvParameters)
|
||||
{
|
||||
MSG *pmsg = NULL;
|
||||
S_SYS_TIME close_time;
|
||||
|
||||
(void)pvParameters;
|
||||
|
||||
delay_ms(1000);
|
||||
|
||||
log_init_mem_para();
|
||||
|
||||
config_time_msg(MSG_SEC);
|
||||
config_time_msg(MSG_MINUTE);
|
||||
|
||||
//发送一个上次断电的告警日志? 这个还有问题,若直接通过复位键复位,系统断电时间是不更新的!!
|
||||
rtc_get_last_close_time(&close_time);
|
||||
log_system_event_generate(&close_time,LOG_TYPE_POWER_OFF,NULL,0);
|
||||
|
||||
//上电先自己发送一个电源上电告警日志
|
||||
log_system_event_generate(NULL,LOG_TYPE_POWER_ON,NULL,0);
|
||||
|
||||
while((pmsg = get_msg(OS_WAIT_FOREVER))!=NULL)
|
||||
{
|
||||
switch(pmsg->type)
|
||||
{
|
||||
case MSG_SEC:
|
||||
task_is_ok();
|
||||
|
||||
break;
|
||||
case MSG_LOG: //有新的系统日志产生,暂存到4K掉电不丢失RAM中,然后有MIN消息去保存
|
||||
if(update_flag)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_save_new_record(pmsg);
|
||||
}
|
||||
break;
|
||||
case MSG_MINUTE:
|
||||
log_check_save_to_e2prom();
|
||||
break;
|
||||
case MSG_LOG_RECORD_RESET:
|
||||
log_record_reset();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(MSG_NEED_TO_FREE(pmsg))
|
||||
free_msg(pmsg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
函 数 名 : log_read_record_by_index
|
||||
功能描述 : 根据序号,读取log日志内容
|
||||
输入参数 : uint32 index 读取起始序号,为0,则表示最新的,越大则表示越旧的日志
|
||||
void *pdata 读取到的日志内容,存到改指针中,
|
||||
输出参数 : 无
|
||||
返 回 值 :实际读取的log条数
|
||||
调用函数 :
|
||||
被调函数 :
|
||||
|
||||
修改历史 :
|
||||
1.日 期 : 2014年1月16日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 新生成函数
|
||||
|
||||
*****************************************************************************/
|
||||
uint32 log_read_record_by_index(uint32 index,void *pdata)
|
||||
{
|
||||
#if USE_LOG_MODULE
|
||||
S_LOG_STRUCT *pdest;
|
||||
uint32 current_index = 0;
|
||||
|
||||
if(index>LOG_MAX_RECORD_NUM)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!pdata)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdest = (S_LOG_STRUCT*)pdata;
|
||||
|
||||
if(log_use_bk_ram_flag)
|
||||
{
|
||||
if(index>pos_log->total_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(pos_log->lastest_index>index)
|
||||
{
|
||||
current_index = pos_log->lastest_index-1-index;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_index = pos_log->lastest_index+LOG_MAX_RECORD_NUM-1-index;
|
||||
}
|
||||
|
||||
if(pos_log->log[current_index].valid==1)
|
||||
{
|
||||
*pdest = pos_log->log[current_index];
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(pdest,0,sizeof(S_LOG_STRUCT));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
S_LOG_STRUCT log_temp;
|
||||
uint32 address;
|
||||
|
||||
if(index>log_e2_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(log_e2_latest_index)
|
||||
{
|
||||
current_index = log_e2_latest_index-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_index = LOG_MAX_RECORD_NUM-1;
|
||||
}
|
||||
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS+current_index*LOG_PER_RECORD_SIZE;
|
||||
|
||||
atmel_read_e2((uint8*)&log_temp,address,LOG_PER_RECORD_SIZE);
|
||||
|
||||
if(log_temp.valid==1)
|
||||
{
|
||||
*pdest = log_temp;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(pdest,0,sizeof(S_LOG_STRUCT));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//清除log信息
|
||||
void log_record_reset(void)
|
||||
{
|
||||
#if USE_LOG_MODULE
|
||||
if(log_use_bk_ram_flag)
|
||||
{
|
||||
pos_log->lastest_index = 0;
|
||||
pos_log->total_num = 0;
|
||||
|
||||
memset(pos_log->log,0,LOG_MAX_RECORD_NUM*LOG_PER_RECORD_SIZE);
|
||||
LOG_SET_ALL_SAVE_BIT();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint32 address = 0;
|
||||
S_LOG_STRUCT log_temp;
|
||||
|
||||
log_e2_latest_index = 0;
|
||||
log_e2_num = 0;
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_INDEX_ADDRESS, log_e2_latest_index);
|
||||
c256_bytewrite2(E2_SYSTEM_LOG_CURRENT_NUM_ADDRESS, log_e2_num);
|
||||
|
||||
memset(&log_temp,0,LOG_PER_RECORD_SIZE);
|
||||
address = E2_SYSTEM_LOG_START_ADDRESS;
|
||||
|
||||
for(i=0;i<LOG_MAX_RECORD_NUM;i++,address+=LOG_PER_RECORD_SIZE)
|
||||
{
|
||||
atmel_write_e2((uint8*)&log_temp,address,LOG_PER_RECORD_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*****************************************************************************
|
||||
函 数 名 : log_system_event_generate
|
||||
功能描述 : 系统事件发生时,调用的函数
|
||||
输入参数 : S_SYS_TIME* ptime 事件发生时间,若为NULL,则有该函数自动填充为当前事件,若有特殊需要,自己手动填写
|
||||
uint32 type 事件发生类型
|
||||
uint8 *pcontent 事件的具体内容 根据需要填写,如"RF_OFF"等
|
||||
uint32 ctlen 时间具体内容的长度
|
||||
输出参数 :
|
||||
返 回 值 : 0: 正常,其他参数,错误
|
||||
调用函数 :
|
||||
被调函数 :
|
||||
|
||||
修改历史 :
|
||||
1.日 期 : 2014年1月16日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 新生成函数
|
||||
|
||||
*****************************************************************************/
|
||||
uint32 log_system_event_generate(S_SYS_TIME* ptime,uint32 type,uint8 *pcontent,uint32 ctlen)
|
||||
{
|
||||
#if USE_LOG_MODULE
|
||||
MSG *pmsg;
|
||||
S_LOG_STRUCT *plog;
|
||||
S_SYS_TIME *pttemp;
|
||||
|
||||
if((type>=LOG_TYPE_END)||(type==LOG_TYPE_INVALID))
|
||||
{
|
||||
return LOG_ERR_PARA_INVALID;
|
||||
}
|
||||
|
||||
pmsg = alloc_msg();
|
||||
if(!pmsg)
|
||||
{
|
||||
return LOG_ERR_ALLOC_MSG_FAILED;
|
||||
}
|
||||
|
||||
plog = alloc_mem(sizeof(S_LOG_STRUCT));
|
||||
if(!plog)
|
||||
{
|
||||
free_msg(pmsg);
|
||||
return LOG_ERR_ALLOC_MEM_FAILED;
|
||||
}
|
||||
|
||||
plog->type = type;
|
||||
if((ctlen)&&(pcontent))
|
||||
{
|
||||
ctlen = ctlen>sizeof(plog->content)?sizeof(plog->content):ctlen;
|
||||
memcpy(plog->content,pcontent,ctlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(plog->content,0,sizeof(plog->content)); //进行清空,防止原先旧数据干扰
|
||||
}
|
||||
if(ptime)
|
||||
{
|
||||
plog->year = ptime->year-2000;
|
||||
plog->month= ptime->month;
|
||||
plog->date = ptime->date;
|
||||
plog->hour = ptime->hour;
|
||||
plog->min = ptime->min;
|
||||
plog->sec = ptime->sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
pttemp = os_get_sys_time_ptr();
|
||||
|
||||
plog->year = pttemp->year-2000;
|
||||
plog->month= pttemp->month;
|
||||
plog->date = pttemp->date;
|
||||
plog->hour = pttemp->hour;
|
||||
plog->min = pttemp->min;
|
||||
plog->sec = pttemp->sec;
|
||||
}
|
||||
|
||||
pmsg->type = MSG_LOG;
|
||||
pmsg->wPara = type;
|
||||
pmsg->lPara = (uint32)plog;
|
||||
|
||||
send_msg(LOG_TASK_ID,pmsg);
|
||||
return LOG_ERR_NO_ERR;
|
||||
#else
|
||||
return LOG_ERR_NO_ERR;
|
||||
#endif
|
||||
}
|
||||
|
||||
//获取当前日志总条数
|
||||
uint32 log_get_total_record_num(void)
|
||||
{
|
||||
#if USE_LOG_MODULE
|
||||
if(log_use_bk_ram_flag)
|
||||
{
|
||||
return pos_log->total_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
return log_e2_num;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#if USE_DEBUG_UART
|
||||
void log_record_printf(void)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint32 j = 0;
|
||||
S_LOG_STRUCT log_temp;
|
||||
uint32 ret_num;
|
||||
const uint8 log_type[][16] = {"NO ERR","POWER_ON","POWER_OFF","PARA_CHANGE","TIME_CHANGE","GPS_UNLOCK","TS_ERR"};
|
||||
|
||||
i = log_get_total_record_num();
|
||||
printf("log total num:%d.\n",i);
|
||||
|
||||
for(j=0;j<i;j++)
|
||||
{
|
||||
ret_num = log_read_record_by_index(j,&log_temp);
|
||||
if((ret_num)&&(log_temp.valid==1))
|
||||
{
|
||||
printf("log num:%d,type:%s,time:20%02d/%02d/%02d %02d:%02d:%02d,",
|
||||
j+1,log_type[log_temp.type],log_temp.year,log_temp.month,log_temp.date,log_temp.hour,log_temp.min,log_temp.sec);
|
||||
if(strlen((char*)log_temp.content))
|
||||
printf("log content:%s\n",log_temp.content);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
/*
|
||||
@TMP_NOT_USED
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "type.h"
|
||||
#include "lcd_task.h"
|
||||
#include "string.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#if LWIP_SNMP
|
||||
|
||||
extern S_ATSC_PARA atsc_para;
|
||||
static char out_buf[16];
|
||||
|
||||
|
||||
void snmp_get_nm_para(uint8 id,uint32 len,void *value)
|
||||
{
|
||||
uint32 temp = 0;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 1:
|
||||
*(uint32 *)value = txfreq_to_hz(atsc_para.rf_para.txfreq);
|
||||
break;
|
||||
case 2:
|
||||
temp = atsc_para.rf_para.power;
|
||||
if(temp >RF_POWER_P_C_ON)
|
||||
temp = RF_POWER_P_C_ON;
|
||||
temp = abs(temp-RF_POWER_ZERO);
|
||||
|
||||
if(atsc_para.rf_para.power>=RF_POWER_ZERO)
|
||||
{
|
||||
sprintf(out_buf,"+%ld.%02lddBm",temp/20,temp%20*5);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(out_buf,"-%ld.%02lddBm",temp/20,temp%20*5);
|
||||
}
|
||||
memcpy((void *)value,out_buf,8);
|
||||
break;
|
||||
case 3: //0:OFF,1:ON.
|
||||
temp = atsc_para.rf_para.agc;
|
||||
|
||||
if(temp==0)
|
||||
{
|
||||
memcpy((void*)value,"AGC:OFF",8);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((void*)value,"AGC:ON",7);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
temp = atsc_para.rf_para.cw;
|
||||
if(temp==0)
|
||||
{
|
||||
memcpy((void*)value,"CW:OFF",7);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((void*)value,"AGC:ON",6);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
temp = atsc_para.rf_para.rf;
|
||||
if(temp==0)
|
||||
{
|
||||
memcpy((void*)value,"RF:OFF",7);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((void*)value,"RF:ON",6);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
temp = atsc_para.system_para.adpc;
|
||||
switch(temp)
|
||||
{
|
||||
case 0:
|
||||
memcpy((void*)value,"ADPC:OFF",9);
|
||||
break;
|
||||
case 1:
|
||||
memcpy((void*)value,"ADPC:HOLD",10);
|
||||
break;
|
||||
case 2:
|
||||
memcpy((void*)value,"ADPC:UPDATE1",13);
|
||||
break;
|
||||
case 3:
|
||||
memcpy((void*)value,"ADPC:UPDATE2",13);
|
||||
break;
|
||||
default:
|
||||
memcpy((void*)value,"ADPC:UnKnow",12);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
void snmp_set_nm_para(uint8 id,uint32 len,void *value)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
/*
|
||||
@STAY_FINAL_PROC:
|
||||
*/
|
||||
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "sntp.h"
|
||||
#include "type.h"
|
||||
#include "sntp_task.h"
|
||||
#include "lcd_task.h"
|
||||
#include "os_task.h"
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "dns.h"
|
||||
|
||||
|
||||
extern void SNTP_REQ(void);
|
||||
extern void delay_ms(uint32 nms);
|
||||
|
||||
|
||||
int getNowTime(void)
|
||||
{
|
||||
//atsc_para.system_para.sntp_date
|
||||
#if 0
|
||||
time_t now = 0;
|
||||
struct tm timeinfo = { 0 };
|
||||
char strftime_buf[72];
|
||||
|
||||
time(&now); //获取网络时间, 64bit的秒计数
|
||||
localtime_r(&now, &timeinfo); //转换成具体的时间参数
|
||||
// strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
|
||||
return timeinfo;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void sntpService(uint8 *pAddr)
|
||||
{
|
||||
ip_addr_t sip;
|
||||
|
||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||
sip.addr = pAddr[0]<<24|pAddr[1]<<16|pAddr[2]<<8|pAddr[3]<<0;
|
||||
sntp_setserver(0, &sip);
|
||||
sntp_init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void stopSNTP(void)
|
||||
{
|
||||
sntp_stop();
|
||||
}
|
||||
|
||||
|
||||
int sntp_enable(uint8 en, uint8 *pAddr)
|
||||
{
|
||||
if(en>1)
|
||||
en = 0;
|
||||
|
||||
if(NULL ==pAddr)
|
||||
return -1;
|
||||
|
||||
stopSNTP();
|
||||
|
||||
if(1 == en)
|
||||
sntpService(pAddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void dnsStart(uint8 *pdns)
|
||||
{
|
||||
ip_addr_t serverip;
|
||||
|
||||
serverip.addr =pdns[0]<<24|pdns[1]<<16|pdns[2]<<8|pdns[3]<<0;
|
||||
dns_setserver(0, &serverip);
|
||||
|
||||
dns_init();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sntp_restart(void)
|
||||
{
|
||||
static uint8 cnt = 0;
|
||||
if(cnt++>10)
|
||||
{
|
||||
cnt = 0;
|
||||
sntp_enable(1, atsc_para.system_para.sntp_sip);
|
||||
}
|
||||
}
|
||||
|
||||
void sntp_task(void * pvParameters)
|
||||
{
|
||||
MSG *pmsg = NULL;
|
||||
|
||||
config_time_msg(MSG_SEC);
|
||||
|
||||
sntpService(atsc_para.system_para.sntp_sip);
|
||||
|
||||
while((pmsg = get_msg(OS_WAIT_FOREVER))!=NULL)
|
||||
{
|
||||
switch(pmsg->type)
|
||||
{
|
||||
case MSG_SEC:
|
||||
task_is_ok(); //任务正常工作
|
||||
sntp_restart();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(MSG_NEED_TO_FREE(pmsg))
|
||||
free_msg(pmsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
|
||||
/*
|
||||
@STAY_FINAL_PROC
|
||||
*/
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
版权所有 (C), 2001-2011, 上海全波通信技术有限公司
|
||||
|
||||
******************************************************************************
|
||||
文 件 名 : swap_data.c
|
||||
版 本 号 : 初稿
|
||||
作 者 : 郭金涛
|
||||
生成日期 : 2013年11月5日
|
||||
最近修改 :
|
||||
功能描述 : 实现数据导入导出交换功能,导出为二进制格式.
|
||||
函数列表 :
|
||||
修改历史 :
|
||||
1.日 期 : 2013年11月5日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 创建文件
|
||||
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "type.h"
|
||||
#include "config.h"
|
||||
|
||||
#if USE_SWAP_DATA
|
||||
//#include "stm32f4x7_eth.h"
|
||||
//#include "stm32f4x7_eth_bsp.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#include "sockets.h"
|
||||
#include "os_task.h"
|
||||
#include "tcp_task.h"
|
||||
#include "cgifuncs.h"
|
||||
#include "os_task.h"
|
||||
#include "eeprom.h"
|
||||
#include "lcd_task.h"
|
||||
#include "i2c_drv.h"
|
||||
#include "uart_user.h"
|
||||
#include "tcp.h"
|
||||
#include "delay.h"
|
||||
#include "general_api.h"
|
||||
#include "sys_config.h"
|
||||
#include "swap_data.h"
|
||||
|
||||
static uint8 swap_rec_buf[SWAP_REC_BUF_MAX];
|
||||
static uint8 swap_send_buf[SWAP_SEND_BUF_MAX];
|
||||
|
||||
|
||||
static uint32 swap_frame_check(uint32 len)
|
||||
{
|
||||
S_SWAP_FRAME *pframe= (S_SWAP_FRAME*)swap_rec_buf;
|
||||
|
||||
|
||||
if(len<SWAP_FRAME_MIN_LEN)
|
||||
return 1;
|
||||
|
||||
if(pframe->header!=SWAP_FRAME_HEADER)
|
||||
return 2;
|
||||
|
||||
if(pframe->im_ex>=2)
|
||||
return 3;
|
||||
|
||||
if(pframe->std!=EXCITER_ISDBT) //需根据当前激励器类型进行更改
|
||||
return 4;
|
||||
|
||||
if(swap_rec_buf[pframe->len+SWAP_FRAME_MIN_LEN-2]!=get_check_sum(swap_rec_buf,pframe->len+SWAP_FRAME_MIN_LEN-2))
|
||||
return 5;
|
||||
|
||||
if(swap_rec_buf[pframe->len+SWAP_FRAME_MIN_LEN-1]!=SWAP_FRAME_TAIL)
|
||||
return 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
函 数 名 : swap_ex_exciter_para
|
||||
功能描述 : 激励器参数导出实现主函数
|
||||
输入参数 : void
|
||||
输出参数 : 无
|
||||
返 回 值 : static
|
||||
调用函数 :
|
||||
被调函数 :
|
||||
|
||||
修改历史 :
|
||||
1.日 期 : 2013年11月11日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 新生成函数
|
||||
|
||||
*****************************************************************************/
|
||||
static uint32 swap_ex_exciter_para(void)
|
||||
{
|
||||
S_SWAP_FRAME *pframe = (S_SWAP_FRAME*)swap_rec_buf;
|
||||
S_SWAP_FRAME *psend = (S_SWAP_FRAME*)swap_send_buf;
|
||||
uint32 send_len = 0;
|
||||
|
||||
|
||||
switch(pframe->cmd&0x7f)
|
||||
{
|
||||
case SWAP_FRAME_DATA_PARA:
|
||||
psend->len = sizeof(S_SYSTEM_PARA);
|
||||
psend->index = 0;
|
||||
psend->total = 0;
|
||||
memcpy(&psend->data[0],&atsc_para.system_para,sizeof(S_SYSTEM_PARA));
|
||||
break;
|
||||
case SWAP_FRAME_DATA_DPD:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
send_len = psend->len+SWAP_FRAME_MIN_LEN;
|
||||
return send_len;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
函 数 名 : swap_im_exciter_para
|
||||
功能描述 : 激励器数据导入实现主函数
|
||||
输入参数 : void
|
||||
输出参数 : 无
|
||||
返 回 值 : static
|
||||
调用函数 :
|
||||
被调函数 :
|
||||
|
||||
修改历史 :
|
||||
1.日 期 : 2013年11月11日
|
||||
作 者 : 郭金涛
|
||||
修改内容 : 新生成函数
|
||||
|
||||
*****************************************************************************/
|
||||
static uint32 swap_im_exciter_para(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static uint32 swap_frame_decode(void)
|
||||
{
|
||||
uint32 send_len = 0;
|
||||
S_SWAP_FRAME *pframe = (S_SWAP_FRAME*)swap_rec_buf;
|
||||
|
||||
if(pframe->im_ex==SWAP_FRAME_EXPORT)
|
||||
{
|
||||
send_len = swap_ex_exciter_para();
|
||||
}
|
||||
else
|
||||
{
|
||||
send_len = swap_im_exciter_para();
|
||||
}
|
||||
return send_len;
|
||||
}
|
||||
static uint32 swap_frame_process(uint32 rec_len)
|
||||
{
|
||||
uint32 ret = 0;
|
||||
|
||||
ret = swap_frame_check(rec_len);
|
||||
if(ret!=0)
|
||||
{
|
||||
swap_printf("swap rec frame format err! code:%d\n",ret);
|
||||
return 0;
|
||||
}
|
||||
return swap_frame_decode();
|
||||
}
|
||||
|
||||
void swap_data_task(void * pvParameters)
|
||||
{
|
||||
struct sockaddr_in server_addr;
|
||||
struct sockaddr_in conn_addr;
|
||||
int sock_fd;
|
||||
int sock_conn;
|
||||
socklen_t addr_len;
|
||||
int err;
|
||||
int length;
|
||||
task_set_ignore_chk(SWAP_TASK_ID);
|
||||
|
||||
(void)pvParameters;
|
||||
vTaskDelay(15);
|
||||
printf("%s init start...\n",__FUNCTION__);
|
||||
|
||||
|
||||
sock_fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock_fd == -1)
|
||||
{
|
||||
printf("%s failed to create swap_data sock_fd!\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr =htonl(INADDR_ANY);
|
||||
server_addr.sin_port = htons(SWAP_TCP_PORT);
|
||||
|
||||
err = lwip_bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
|
||||
if (err < 0)
|
||||
{
|
||||
printf("%s failed to bind sock_fd!\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
err = lwip_listen(sock_fd,1);
|
||||
if (err < 0)
|
||||
{
|
||||
printf("%s failed to listen sock_fd!\n",__FUNCTION__);
|
||||
}
|
||||
|
||||
addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
printf("%s init over.\n",__FUNCTION__);
|
||||
|
||||
while(1)
|
||||
{
|
||||
sock_conn = lwip_accept(sock_fd, (struct sockaddr *)&conn_addr, &addr_len);
|
||||
while(sock_conn!=-1)
|
||||
{
|
||||
length = lwip_recv(sock_conn, swap_rec_buf, SWAP_REC_BUF_MAX, 0);
|
||||
if(length)
|
||||
{
|
||||
length = swap_frame_process(length);
|
||||
if(length)
|
||||
{
|
||||
lwip_send(sock_conn, swap_send_buf,length, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lwip_close(sock_conn);
|
||||
sock_conn = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,708 @@
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> /* netdb is necessary for struct hostent */
|
||||
|
||||
|
||||
|
||||
#include "../inc/isys_com.h"
|
||||
#include "../inc/isys_config.h"
|
||||
#include "../inc/main.h"
|
||||
#include "../inc/mq.h"
|
||||
#include "../inc/lcd_task.h"
|
||||
#include "../inc/tcp_task.h"
|
||||
#include "../inc/iweb_task.h"
|
||||
#include "../inc/uart_user.h"
|
||||
#include "../inc/tcp_autocal.h"
|
||||
#include "../inc/config.h"
|
||||
#include "../inc/type.h"
|
||||
#include "../inc/dpd_proc.h"
|
||||
#include "../inc/os_task.h"
|
||||
|
||||
#include "../inc/http_get.h"
|
||||
|
||||
|
||||
//#include "http_get.h"
|
||||
#define USE_AUTO_CALIBRATION 1
|
||||
|
||||
#if USE_AUTO_CALIBRATION
|
||||
st_AUTO_CAL_PARA st_autocal;
|
||||
S_AUTOCAL_BASE_PARA acal_base;
|
||||
st_DEV_LINK dev_link;
|
||||
|
||||
#pragma pack(4)
|
||||
static uint8 tcp_input_buf[TCP_AUTOCAL_REMOTE_MAX_REC_LEN] = {0};
|
||||
static uint8 tcp_output_buf[TCP_AUTOCAL_REMOTE_MAX_SEND_LEN] = {0};
|
||||
//static uint8 tcp_pro_buf[TCP_AUTOCAL_REMOTE_MAX_PRO_LEN] = {0};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
extern void udp_trigger_adpc(uint8 adpc);
|
||||
|
||||
//extern S_CTTB_PARA cttb_para;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 fwd_power;
|
||||
uint32 freq_ch;
|
||||
uint32 band;
|
||||
|
||||
uint32 lmid;
|
||||
uint32 umid;
|
||||
uint32 snr;
|
||||
uint32 adpc;
|
||||
uint32 adpc_err;
|
||||
uint32 rf;
|
||||
|
||||
}S_DEV_EXC_PARA2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 ts_in;
|
||||
uint16 ts_state;
|
||||
uint32 ts_rate;
|
||||
uint16 ts_under;
|
||||
uint16 reserved;
|
||||
}S_DEV_AOTD_EXC_PARA;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 band;
|
||||
uint32 freq_ch;
|
||||
uint32 fwd_power;
|
||||
uint32 adpc;
|
||||
uint32 rf;
|
||||
}S_EXC_SET_PARA2;
|
||||
|
||||
#define NET_BW_6M 0x0c
|
||||
#define NET_BW_7M 0x0b
|
||||
#define NET_BW_8M 0x0a
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
// -10.0dBm -1000
|
||||
int32 conv_exc_power_to_db(uint16 inpow)//放大100被
|
||||
{
|
||||
int32 outpow;
|
||||
uint16 power;
|
||||
power = inpow;
|
||||
//power -25到+5可调 内部值 0-600 0-500 -25~0 500-600 0~5 一个代表0.05db
|
||||
if(inpow >RF_POWER_P_C_ON)
|
||||
inpow = RF_POWER_P_C_ON;
|
||||
inpow = inpow>=RF_POWER_ZERO?(inpow-RF_POWER_ZERO):(RF_POWER_ZERO - inpow);
|
||||
|
||||
outpow = ((uint16)(inpow/20)*100+(inpow%20)*5);
|
||||
|
||||
if(power>RF_POWER_ZERO)outpow=outpow;
|
||||
else outpow=-outpow;
|
||||
|
||||
return outpow;
|
||||
}
|
||||
|
||||
|
||||
uint32 get_check_sum_long(const void *p,uint32 len)
|
||||
{
|
||||
uint32 sum = 0;
|
||||
uint8 *pstr = (uint8*)p;
|
||||
|
||||
while(len--)
|
||||
sum+=*pstr++;
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void* tcp_frame_checkout_pro(const uint8 *pinbuf,const uint32 rec_len,uint32* pret)
|
||||
{
|
||||
S_AUTOCAL_TCP_FRAME *pframe;
|
||||
uint8* pusebuf;
|
||||
uint16 calc_sum;
|
||||
uint16 frame_sum;
|
||||
uint32 i;
|
||||
|
||||
if(rec_len<TCP_AUTOCAL_FRAME_LEN_WITHOUT_DATA)
|
||||
{
|
||||
*pret = TCP_AUTOCAL_ERR_UNKNOW_FRAME;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pusebuf = (uint8*)pinbuf;
|
||||
for(i=0;i<=rec_len-TCP_AUTOCAL_FRAME_LEN_WITHOUT_DATA;i++,pusebuf++)
|
||||
{
|
||||
//非4字节对齐地址,不做处理
|
||||
/*if(((uint32)pusebuf)&3)
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
pframe = (S_AUTOCAL_TCP_FRAME*)pusebuf;
|
||||
|
||||
if(pframe->header!=TCP_AUTOCAL_FRAME_HEADER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(pframe->length>=TCP_AUTOCAL_REMOTE_MAX_REC_LEN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(pframe->length>rec_len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if(pframe->dst_dev_id!=dev_id){
|
||||
// continue;
|
||||
//}
|
||||
//命令类型不为读或写
|
||||
if((pframe->cmd_type&0xfff)>=CMD_TYPE_END)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//更具体的可到读写函数中再做判断
|
||||
if((pframe->cmd_index>E_READ_DEV_CMD_END)&&(pframe->cmd_index>E_WRITE_DEV_CMD_END))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//小端序,低字节在前,高字节在后
|
||||
calc_sum = get_check_sum_long(pinbuf,pframe->length-TCP_AUTOCAL_FRAME_NOT_SUM_LEN);
|
||||
frame_sum = (pinbuf[pframe->length-4])|(pinbuf[pframe->length-3]<<8);
|
||||
if(calc_sum!=frame_sum)
|
||||
{
|
||||
*pret = TCP_AUTOCAL_ERR_CHECK_SUM;
|
||||
return pframe;
|
||||
}
|
||||
if( ((pinbuf[pframe->length-2])|(pinbuf[pframe->length-1]<<8))!=TCP_AUTOCAL_FRAME_TAIL)
|
||||
{
|
||||
*pret = TCP_AUTOCAL_ERR_FRAME_FORAMT;
|
||||
return pframe;
|
||||
}
|
||||
*pret = TCP_AUTOCAL_ERR_NONE;
|
||||
return pframe;
|
||||
}
|
||||
*pret = TCP_AUTOCAL_ERR_FRAME_FORAMT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tcp_frame_sum_tail(uint8* pout,uint32 frame_len)
|
||||
{
|
||||
uint16 calc_sum = 0;
|
||||
|
||||
calc_sum = get_check_sum_long(pout,frame_len-TCP_AUTOCAL_FRAME_NOT_SUM_LEN);
|
||||
|
||||
pout[frame_len-4] = calc_sum;
|
||||
pout[frame_len-3] = calc_sum>>8;
|
||||
pout[frame_len-2] = (uint8)TCP_AUTOCAL_FRAME_TAIL;
|
||||
pout[frame_len-1] = TCP_AUTOCAL_FRAME_TAIL>>8;
|
||||
}
|
||||
|
||||
static uint32 tcp_frame_ret_err_pro2(S_AUTOCAL_TCP_FRAME* pinframe,S_AUTOCAL_TCP_FRAME* poutframe,uint32 err_code,uint16 dev_type)
|
||||
{
|
||||
if(pinframe==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
poutframe->header = TCP_AUTOCAL_FRAME_HEADER;
|
||||
poutframe->length = TCP_AUTOCAL_FRAME_LEN_WITHOUT_DATA+4;
|
||||
|
||||
if(dev_type==DEV_METER_ID){
|
||||
poutframe->src_dev_id = DEV_METER_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
else if(dev_type==DEV_PA_ID){
|
||||
poutframe->src_dev_id = DEV_PA_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
else if(dev_type==DEV_EXCITER_ID){
|
||||
poutframe->src_dev_id = DEV_EXCITER_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
|
||||
poutframe->data[0] = err_code;
|
||||
poutframe->cmd_type = (pinframe->cmd_type&0xfff)|TCP_AUTOCAL_RET_TYPE_RET|TCP_AUTOCAL_FRAME_ERR;
|
||||
poutframe->cmd_index = pinframe->cmd_index;
|
||||
tcp_frame_sum_tail((uint8*)poutframe,poutframe->length);
|
||||
|
||||
return poutframe->length;
|
||||
}
|
||||
|
||||
|
||||
static uint32 tcp_frame_ret_ok_pro2(S_AUTOCAL_TCP_FRAME* pinframe,S_AUTOCAL_TCP_FRAME* poutframe,uint32 data_len,uint16 dev_type)
|
||||
{
|
||||
if((pinframe==NULL)||(poutframe==NULL))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
poutframe->header = TCP_AUTOCAL_FRAME_HEADER;
|
||||
poutframe->length = TCP_AUTOCAL_FRAME_LEN_WITHOUT_DATA+data_len;
|
||||
|
||||
if(dev_type==DEV_METER_ID){
|
||||
poutframe->src_dev_id = DEV_METER_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
else if(dev_type==DEV_PA_ID){
|
||||
poutframe->src_dev_id = DEV_PA_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
else if(dev_type==DEV_EXCITER_ID){
|
||||
poutframe->src_dev_id = DEV_EXCITER_ID;
|
||||
poutframe->dst_dev_id = DEV_REMOTE_PC_ID;
|
||||
}
|
||||
|
||||
poutframe->cmd_type = (pinframe->cmd_type&0x7fff)|TCP_AUTOCAL_RET_TYPE_RET;
|
||||
poutframe->cmd_index = pinframe->cmd_index;
|
||||
|
||||
tcp_frame_sum_tail((uint8*)poutframe,poutframe->length);
|
||||
|
||||
return poutframe->length;
|
||||
}
|
||||
|
||||
static uint32 tcp_read_aodt_exc_para(S_AUTOCAL_TCP_FRAME* pinframe,uint8* poutbuf)
|
||||
{
|
||||
S_AUTOCAL_TCP_FRAME *poutframe = (S_AUTOCAL_TCP_FRAME*)poutbuf;
|
||||
S_DEV_AOTD_EXC_PARA *pinfo = (S_DEV_AOTD_EXC_PARA*)poutframe->data;
|
||||
|
||||
uint16 total_cur=0;
|
||||
int32 loc_db;
|
||||
|
||||
S_ATSC_PARA *pSysPara = &atsc_para;
|
||||
|
||||
memset(pinfo,0,sizeof(S_DEV_AOTD_EXC_PARA));
|
||||
|
||||
pinfo->ts_in = pSysPara->log_para.asi_input;
|
||||
pinfo->ts_state = pSysPara->log_para.input_ok_flag;
|
||||
pinfo->ts_rate = pSysPara->log_para.ts_rate;
|
||||
|
||||
pinfo->ts_under = (pSysPara->log_para.ts_under&0x1);
|
||||
pinfo->reserved = 0;
|
||||
|
||||
return tcp_frame_ret_ok_pro2(pinframe,poutframe,sizeof(S_DEV_AOTD_EXC_PARA),DEV_EXCITER_ID);
|
||||
}
|
||||
|
||||
static uint32 tcp_read_exc_para2(S_AUTOCAL_TCP_FRAME* pinframe,uint8* poutbuf)
|
||||
{
|
||||
S_AUTOCAL_TCP_FRAME *poutframe = (S_AUTOCAL_TCP_FRAME*)poutbuf;
|
||||
S_DEV_EXC_PARA2 *pinfo = (S_DEV_EXC_PARA2*)poutframe->data;
|
||||
uint16 total_cur=0;
|
||||
int32 loc_db;
|
||||
|
||||
S_ATSC_PARA *pSysPara = &atsc_para;
|
||||
|
||||
memset(pinfo,0,sizeof(S_DEV_EXC_PARA2));
|
||||
|
||||
loc_db = conv_exc_power_to_db(pSysPara->rf_para.power);//cttb_para.rf_para.power
|
||||
|
||||
pinfo->fwd_power = loc_db;
|
||||
pinfo->freq_ch = pSysPara->rf_para.txfreq; //cttb_para.rf_para.txfreq;
|
||||
pinfo->band = NET_BW_6M;
|
||||
|
||||
/*if(cttb_para.system_para.baud_width==BW_8M)
|
||||
pinfo->band = NET_BW_8M;
|
||||
else if(cttb_para.system_para.baud_width==BW_7M)
|
||||
pinfo->band = NET_BW_7M;
|
||||
else if(cttb_para.system_para.baud_width==BW_6M)
|
||||
pinfo->band = NET_BW_6M;*/
|
||||
|
||||
pinfo->lmid = pSysPara->log_para.l_imd/2;//cttb_para.log_para.lid;
|
||||
pinfo->umid = pSysPara->log_para.u_imd/2;//cttb_para.log_para.uid;
|
||||
pinfo->snr = pSysPara->log_para.tsnr; //cttb_para.log_para.snr;
|
||||
|
||||
pinfo->adpc = pSysPara->system_para.adpc; //cttb_para.system_para.adpc;//atsc_para.log_para.adpc;
|
||||
pinfo->adpc_err = pSysPara->system_para.adpc_err;//cttb_para.system_para.adpc_err;
|
||||
pinfo->rf = pSysPara->rf_para.rf; //cttb_para.rf_para.rf;
|
||||
|
||||
return tcp_frame_ret_ok_pro2(pinframe,poutframe,sizeof(S_DEV_EXC_PARA2),DEV_EXCITER_ID);
|
||||
}
|
||||
|
||||
|
||||
static uint32 tcp_remote_read_exc_pro2(S_AUTOCAL_TCP_FRAME* pinframe,uint8* poutbuf)
|
||||
{
|
||||
if(pinframe->cmd_index>=E_READ_DEV_CMD_END)
|
||||
return tcp_frame_ret_err_pro2(pinframe,(S_AUTOCAL_TCP_FRAME*)poutbuf,TCP_AUTOCAL_ERR_CMD_INDEX,DEV_PA_ID);
|
||||
|
||||
switch(pinframe->cmd_index)
|
||||
{
|
||||
/*case 0x1001://功率计
|
||||
return tcp_read_meter_para(pinframe,tcp_output_buf);
|
||||
break;*/
|
||||
/*case 0x2001://功放
|
||||
return tcp_read_pa_para(pinframe,tcp_output_buf);
|
||||
break;
|
||||
case 0x2002://功放
|
||||
return tcp_read_pa_para2(pinframe,tcp_output_buf);
|
||||
break;*/
|
||||
|
||||
case 0x3002://激励器
|
||||
return tcp_read_exc_para2(pinframe,poutbuf);
|
||||
break;
|
||||
|
||||
case 0x3006://激励器-室外机自动接口检测
|
||||
return tcp_read_aodt_exc_para(pinframe,poutbuf);
|
||||
break;
|
||||
|
||||
default:break;
|
||||
}
|
||||
|
||||
return tcp_frame_ret_err_pro2(pinframe,(S_AUTOCAL_TCP_FRAME*)poutbuf,TCP_AUTOCAL_ERR_CMD_INDEX,DEV_PA_ID);
|
||||
}
|
||||
|
||||
|
||||
void udp_set_exc_db_power(int16 db_power)
|
||||
{
|
||||
uint16 temp;
|
||||
uint8 int_val;
|
||||
uint8 dec_val;
|
||||
uint8 sign;
|
||||
|
||||
//set db
|
||||
if(db_power>0){
|
||||
sign = 0;
|
||||
temp = db_power;
|
||||
}
|
||||
else{
|
||||
sign = 1;
|
||||
temp = -db_power;
|
||||
|
||||
}
|
||||
int_val = temp/100;
|
||||
dec_val = (temp%100)*20/100;
|
||||
|
||||
//设置功率
|
||||
//Net_write_Power(sign,int_val,dec_val);
|
||||
|
||||
/*if(tmp_power<=RF_POWER_P_C_ON)
|
||||
{
|
||||
if(atsc_para.wj_para.p_c)
|
||||
{
|
||||
if(tmp_power>RF_POWER_P_C_ON)
|
||||
tmp_power = RF_POWER_P_C_ON;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tmp_power>RF_POWER_MAX)
|
||||
tmp_power = RF_POWER_MAX;
|
||||
}
|
||||
rf_power_set_new(tmp_power);
|
||||
}*/
|
||||
}
|
||||
#if 0//cttb_6.0
|
||||
uint32 usr_Net_write_RF(uint8 param)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void usr_load_default_rf_t(S_CGI_RF_PARA_T *ppara)
|
||||
{
|
||||
ppara->hz = cttb_para.rf_para.hz;
|
||||
ppara->power = cttb_para.rf_para.power;
|
||||
ppara->txfreq= cttb_para.rf_para.txfreq;
|
||||
ppara->cw = cttb_para.rf_para.cw;
|
||||
ppara->rf = cttb_para.rf_para.rf;
|
||||
ppara->agc = cttb_para.rf_para.agc;
|
||||
}
|
||||
|
||||
static void usr_save_rf_para(S_CGI_RF_PARA_T *ppara)
|
||||
{
|
||||
|
||||
if((cttb_para.rf_para.agc==ppara->agc)&&(ppara->agc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
remote_set_power_process(ppara->power);
|
||||
|
||||
cttb_para.rf_para.txfreq = ppara->txfreq;
|
||||
cttb_para.rf_para.hz = ppara->hz; //hz power 已经在接收时处理好
|
||||
cttb_para.rf_para.cw = ppara->cw;
|
||||
cttb_para.rf_para.rf = ppara->rf;
|
||||
cttb_para.rf_para.agc = ppara->agc;
|
||||
e2rom_save_rf(&cttb_para.rf_para);
|
||||
fpga_save_rf(&cttb_para.rf_para);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
uint32 db_to_local_power(int32 db_power)
|
||||
{
|
||||
uint16 temp;
|
||||
uint8 sign;
|
||||
uint32 value;
|
||||
int32 fpower;
|
||||
|
||||
uint32 ret_power;
|
||||
|
||||
if(db_power>0){
|
||||
sign = 0;
|
||||
temp = db_power;
|
||||
}
|
||||
else{
|
||||
sign = 1;
|
||||
temp = -db_power;
|
||||
|
||||
}
|
||||
|
||||
value = (temp/100)*20 + (temp%100)*20/100; //一单位0.05
|
||||
|
||||
if(sign)//负值 200对应0db,最大-10,最大+5 0~300
|
||||
fpower = 0-value;
|
||||
else
|
||||
fpower =(int32)value;
|
||||
|
||||
|
||||
fpower+=RF_POWER_ZERO;
|
||||
if(fpower>RF_POWER_MAX)
|
||||
fpower = RF_POWER_MAX;
|
||||
if(fpower<0)
|
||||
fpower = 0;
|
||||
|
||||
ret_power = (uint32)fpower;
|
||||
|
||||
return ret_power;
|
||||
}
|
||||
int32 g_dbg_rec_power = 0;
|
||||
static uint32 tcp_remote_write_exc_pro2(S_AUTOCAL_TCP_FRAME* pinframe,uint8* poutbuf)
|
||||
{
|
||||
S_EXC_SET_PARA2 *ppara = (S_EXC_SET_PARA2 *)pinframe->data;
|
||||
S_EXC_SET_PARA2 exc_set={0};
|
||||
int32 loc_db=0;
|
||||
int32 rec_power;
|
||||
uint32 tmp_pwr;
|
||||
|
||||
S_ATSC_PARA *pSysPara = &atsc_para;
|
||||
S_CGI_RF tmp_rf_para = {0};//S_CGI_RF_PARA_T tmp_rf_para={0};
|
||||
|
||||
//band
|
||||
/*if(ppara->band != cttb_para.wl_para.band)
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
//freq
|
||||
if(ppara->freq_ch != pSysPara->rf_para.txfreq)//cttb_para.rf_para.txfreq
|
||||
{
|
||||
/*usr_load_default_rf_t(&tmp_rf_para);
|
||||
tmp_rf_para.txfreq = ppara->freq_ch;
|
||||
usr_save_rf_para(&tmp_rf_para);*/
|
||||
|
||||
// how to switch freq ...
|
||||
if(ppara->freq_ch>= FREQ_MIN_V1&& ppara->freq_ch <= FREQ_6M_MAX_U){
|
||||
/*http_load_rf(&tmp_rf_para);
|
||||
tmp_rf_para.txfreq = ppara->freq_ch;
|
||||
http_write_rf(&tmp_rf_para);*/
|
||||
|
||||
usr_http_write_freq(ppara->freq_ch);
|
||||
}
|
||||
}
|
||||
|
||||
if(ppara->rf != pSysPara->rf_para.rf && ppara->fwd_power != 0xf0f0f0f0)//cttb_para.rf_para.rf
|
||||
{
|
||||
if(ppara->rf==0||ppara->rf==1){
|
||||
/*usr_load_default_rf_t(&tmp_rf_para);
|
||||
tmp_rf_para.rf = ppara->rf;
|
||||
usr_save_rf_para(&tmp_rf_para);*/
|
||||
|
||||
// how to switch rf ...
|
||||
http_load_rf(&tmp_rf_para);
|
||||
tmp_rf_para.rf = ppara->rf;
|
||||
http_write_rf(&tmp_rf_para);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loc_db = conv_exc_power_to_db(pSysPara->rf_para.power);//cttb_para.rf_para.power
|
||||
rec_power = (int32)ppara->fwd_power;
|
||||
|
||||
g_dbg_rec_power = (int32)ppara->fwd_power;
|
||||
|
||||
//fwd_power
|
||||
if(rec_power != loc_db && rec_power != 0xf0f0f0f0)
|
||||
{
|
||||
if(rec_power>=-25*100 && rec_power <= 10*100){
|
||||
|
||||
/*usr_load_default_rf_t(&tmp_rf_para);
|
||||
tmp_rf_para.power = db_to_local_power(rec_power);
|
||||
if(tmp_rf_para.power<220)
|
||||
usr_save_rf_para(&tmp_rf_para);*/
|
||||
|
||||
// how to set pwr ...
|
||||
http_load_rf(&tmp_rf_para);
|
||||
if(rec_power>0){
|
||||
tmp_rf_para.power[0] = 0;
|
||||
tmp_pwr = rec_power;
|
||||
}
|
||||
else{
|
||||
tmp_rf_para.power[0] = 1;
|
||||
tmp_pwr = -rec_power;
|
||||
}
|
||||
tmp_rf_para.power[1] = (uint8)(tmp_pwr/100);
|
||||
tmp_rf_para.power[2] = (uint8)((tmp_pwr%100)/5);
|
||||
http_write_rf(&tmp_rf_para);
|
||||
}
|
||||
}
|
||||
|
||||
//adpc
|
||||
if(pSysPara->system_para.adpc != ppara->adpc && ppara->adpc!= 0xf0f0f0f0){ //cttb_para.system_para.adpc
|
||||
udp_trigger_adpc(ppara->adpc);
|
||||
}
|
||||
|
||||
if(ppara->adpc == 0){
|
||||
remote_set_dpd_clr();
|
||||
}
|
||||
|
||||
return tcp_frame_ret_ok_pro2(pinframe,(S_AUTOCAL_TCP_FRAME*)poutbuf,ERR_NO_ERR,DEV_EXCITER_ID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint32 tcp_remote_process(uint8 *precbuf,uint32 len)
|
||||
{
|
||||
uint32 send_len = 0;
|
||||
uint32 ret;
|
||||
S_AUTOCAL_TCP_FRAME *pframe;
|
||||
|
||||
pframe = tcp_frame_checkout_pro(precbuf,len,&ret);
|
||||
|
||||
if((ret!=TCP_AUTOCAL_ERR_NONE)||(pframe==NULL))
|
||||
{
|
||||
send_len = tcp_frame_ret_err_pro2(pframe,(S_AUTOCAL_TCP_FRAME*)tcp_output_buf,ret,DEV_EXCITER_ID);
|
||||
//send_len = tcp_frame_ret_err_client_pro(pframe,(S_AUTOCAL_TCP_FRAME*)tcp_output_buf,ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(pframe->cmd_type&0xfff)
|
||||
{
|
||||
case CMD_TYPE_READ:
|
||||
memset(tcp_output_buf,0,sizeof(tcp_output_buf));
|
||||
send_len = tcp_remote_read_exc_pro2(pframe,tcp_output_buf);
|
||||
break;
|
||||
case CMD_TYPE_SET:
|
||||
memset(tcp_output_buf,0,sizeof(tcp_output_buf));
|
||||
send_len = tcp_remote_write_exc_pro2(pframe,tcp_output_buf);
|
||||
break;
|
||||
default:
|
||||
send_len = tcp_frame_ret_err_pro2(pframe,(S_AUTOCAL_TCP_FRAME*)tcp_output_buf,TCP_AUTOCAL_ERR_CMD_TYPE,DEV_PA_ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return send_len;
|
||||
}
|
||||
|
||||
/*
|
||||
void auto_udp_task(void * pvParameters)
|
||||
{
|
||||
struct sockaddr_in server_addr;
|
||||
int sock_pa_fd;
|
||||
int err;
|
||||
int length;
|
||||
struct sockaddr from;
|
||||
socklen_t fromlen;
|
||||
|
||||
task_set_ignore_chk(AUTO_UDP_TASK_ID);
|
||||
|
||||
printf("%s init start...\n",__FUNCTION__);
|
||||
|
||||
sock_pa_fd = lwip_socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sock_pa_fd == -1)
|
||||
{
|
||||
printf("failed to create udp sock_fd!\n");
|
||||
sock_pa_fd = sock_pa_fd;
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr =htonl(INADDR_ANY);
|
||||
server_addr.sin_port = htons(EXC_UDP_PORT);
|
||||
|
||||
err = lwip_bind(sock_pa_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
|
||||
if(err < 0)
|
||||
{
|
||||
printf("failed to bind sock_fd!\n");
|
||||
}
|
||||
|
||||
while(1)
|
||||
{ //阻塞型
|
||||
memset(tcp_input_buf, 0, sizeof(tcp_input_buf));
|
||||
|
||||
length = lwip_recvfrom(sock_pa_fd,tcp_input_buf,TCP_AUTOCAL_REMOTE_MAX_REC_LEN, 0,&from,&fromlen);
|
||||
if(length)
|
||||
{
|
||||
memset(tcp_output_buf,0,sizeof(tcp_output_buf));
|
||||
length = tcp_remote_process(tcp_input_buf,length);
|
||||
lwip_sendto(sock_pa_fd, tcp_output_buf,length, 0,&from,fromlen);//length
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
void * auto_adj_thr(void * args)
|
||||
{
|
||||
int udo_sock_fd = 0;
|
||||
int ret = 0;
|
||||
struct sockaddr_in serverAddr;
|
||||
struct sockaddr from;
|
||||
socklen_t fromlen;
|
||||
int port;
|
||||
int recvlen = 0;
|
||||
int length;
|
||||
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"[.thr.] auto_adj_thr Start.\n");
|
||||
|
||||
/* creat udp socket */
|
||||
udo_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(udo_sock_fd == -1){
|
||||
log_printf(LOG_ERR,I_NOUSED," tco_sock_fd socket fail.\n");
|
||||
return ((void*)NULL);
|
||||
}
|
||||
|
||||
memset(&serverAddr, 0, sizeof(serverAddr));
|
||||
serverAddr.sin_family = PF_INET;
|
||||
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serverAddr.sin_port = htons(EXC_UDP_PORT);
|
||||
|
||||
if(bind(udo_sock_fd,(struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0)
|
||||
{
|
||||
log_printf(LOG_DEBUG,I_NOUSED," bind 0.0.0.0:%d failed\n",port);
|
||||
close(udo_sock_fd);
|
||||
return ((void*)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_printf(LOG_DEBUG,I_NOUSED," bind 0.0.0.0:%d ok\n",port);
|
||||
}
|
||||
|
||||
|
||||
while(1) {
|
||||
memset(tcp_input_buf, 0, sizeof(tcp_input_buf));
|
||||
// block
|
||||
recvlen = recvfrom(udo_sock_fd, tcp_input_buf, TCP_AUTOCAL_REMOTE_MAX_REC_LEN, 0, &from, &fromlen);
|
||||
if(recvlen) {
|
||||
//printf("recv_len=%d\n",recvlen);
|
||||
//printf(" rx_buff %02X %02X %02X \n", tcp_input_buf[0], tcp_input_buf[1], tcp_input_buf[2]);
|
||||
memset(tcp_output_buf,0,sizeof(tcp_output_buf));
|
||||
length = tcp_remote_process(tcp_input_buf,recvlen);
|
||||
if(length) {
|
||||
sendto(udo_sock_fd, tcp_output_buf, length, 0, &from, fromlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,311 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../inc/tsoip.h"
|
||||
#include "../inc/fpga.h"
|
||||
#include "../inc/isys_config.h"
|
||||
#include "../inc/i2c_drv.h"
|
||||
#include "../inc/delay.h"
|
||||
#include "../inc/eeprom.h"
|
||||
#include "../inc/iweb_task.h"
|
||||
#include "../inc/main.h"
|
||||
#include "../inc/msg.h"
|
||||
#include "../inc/lcd_task.h"
|
||||
#include "../inc/upgrade.h"
|
||||
#include "../inc/isys_com.h"
|
||||
|
||||
|
||||
|
||||
|
||||
volatile S_TSOIP_CONFIG_PARA i2c_para_bak;
|
||||
static volatile uint32 ip2ts_para_changed = 0;
|
||||
|
||||
extern S_ATSC_PARA atsc_para;
|
||||
extern S_IP2TS_PARA ip2ts[2]; // 20220214 add by oneshu
|
||||
|
||||
extern TS_NET_STRUCT ts_net_para;
|
||||
extern TS_NET_STRUCT ts_net_para2;//h20190218 新增
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void change_tsoip_param_flg(int flg)
|
||||
{
|
||||
ip2ts_para_changed = 1;
|
||||
}
|
||||
|
||||
static void i2c_fpga_change_boot(void)
|
||||
{
|
||||
uint8 data = 0;
|
||||
uint32 i = 0;
|
||||
|
||||
while((data != 0x10) && (i < 10))
|
||||
{
|
||||
tsoip_byte_write(TSOIP_1, FPGA_UPGRADE_I2C_REG_ADDRES, 0x10);
|
||||
delay_ms(20);
|
||||
data = tsoip_byte_read(TSOIP_1, FPGA_UPGRADE_I2C_REG_ADDRES);
|
||||
}
|
||||
|
||||
if(data == 0x10)
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"fpga change to boot ok\n");
|
||||
else
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"fpga change to boot err\n");
|
||||
}
|
||||
void inset_tsoip_instance(TSOIP_INSTANCE *p_tsoip_instance, S_TSOIP_CONFIG_PARA *p_tsoip_cfg_param)
|
||||
{
|
||||
if(p_tsoip_instance==NULL||p_tsoip_cfg_param==NULL)
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
for(i=0; i<4; i++){
|
||||
p_tsoip_instance->ip[i] = p_tsoip_cfg_param->ip[i];
|
||||
p_tsoip_instance->multicast_ip[i] = p_tsoip_cfg_param->multi_address[i];
|
||||
}
|
||||
p_tsoip_instance->enable_multicast = p_tsoip_cfg_param->receive_type;
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"insert ts mult=%s:port%d\n",
|
||||
p_tsoip_cfg_param->receive_type==IP2TS_I2C_ADD_MULTI?"enable":"disable",p_tsoip_cfg_param->port);
|
||||
p_tsoip_instance->port = p_tsoip_cfg_param->port;
|
||||
}
|
||||
|
||||
static void i2c_save_ip2ts_para(void)
|
||||
{
|
||||
#if 0
|
||||
static uint32 flag_bak = 0;
|
||||
uint32 rec_ip_bak = 0;
|
||||
uint32 rec_ip_new = 0;
|
||||
uint16 rec_port_bak = 0;
|
||||
|
||||
if(ip2ts_para_changed==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
printf("[%s,%d]\n", __FUNCTION__,__LINE__);
|
||||
//持续有参数设置
|
||||
if(flag_bak != ip2ts_para_changed)
|
||||
{
|
||||
flag_bak = ip2ts_para_changed;
|
||||
printf("[%s,%d]\n", __FUNCTION__,__LINE__);
|
||||
return;
|
||||
}
|
||||
printf("[%s,%d]\n", __FUNCTION__,__LINE__);
|
||||
|
||||
|
||||
if(!memcmp(&ip2ts.tsoip_config_para,(const void*)&i2c_para_bak,sizeof(i2c_para_bak)-4)) //后8个字节在收端为只读
|
||||
{
|
||||
ip2ts_para_changed = 0;
|
||||
flag_bak = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(i2c_para_bak.fpga_upgrade)
|
||||
{
|
||||
i2c_fpga_change_boot();
|
||||
i2c_para_bak.fpga_upgrade = 0; //切换到升级模式,fpga保存无效,但还可以保存本地E2
|
||||
}
|
||||
|
||||
IP_DATA(rec_ip_bak,
|
||||
ip2ts.tsoip_config_para.multi_address[0],
|
||||
ip2ts.tsoip_config_para.multi_address[1],
|
||||
ip2ts.tsoip_config_para.multi_address[2],
|
||||
ip2ts.tsoip_config_para.multi_address[3]);
|
||||
|
||||
rec_port_bak = ip2ts.tsoip_config_para.port;
|
||||
|
||||
if(i2c_para_bak.para_reset)
|
||||
{
|
||||
printf("IP2TS PARA RESET...\n");
|
||||
e2rom_load_default_param_t_tsoip(0);
|
||||
e2rom_read_config_tsoip((S_TSOIP_CONFIG_PARA*)&i2c_para_bak);
|
||||
}
|
||||
|
||||
printf("%s\n", __FUNCTION__);
|
||||
//检测变化的参数,并存入E2PROM 全部固定存效率有点低
|
||||
e2rom_save_config_tsoip((S_TSOIP_CONFIG_PARA*)&i2c_para_bak);
|
||||
fpga_save_config_tsoip((S_TSOIP_CONFIG_PARA*)&i2c_para_bak);
|
||||
|
||||
//正常参数配置完后,会有复位命令
|
||||
if(i2c_para_bak.rst)
|
||||
{
|
||||
//复位FPGA功能,暂不响应
|
||||
i2c_para_bak.rst = 0;
|
||||
}
|
||||
memcpy(&ip2ts.tsoip_config_para, (void*)&i2c_para_bak, sizeof(S_TSOIP_CONFIG_PARA));
|
||||
ip2ts_para_changed = 0;
|
||||
flag_bak = 0;
|
||||
|
||||
IP_DATA(rec_ip_new,
|
||||
ip2ts.tsoip_config_para.multi_address[0],
|
||||
ip2ts.tsoip_config_para.multi_address[1],
|
||||
ip2ts.tsoip_config_para.multi_address[2],
|
||||
ip2ts.tsoip_config_para.multi_address[3]);
|
||||
|
||||
//接收地址有变化,要重新初始化组播域信息
|
||||
if((rec_ip_new != rec_ip_bak)||(rec_port_bak != ip2ts.tsoip_config_para.port))
|
||||
{
|
||||
TSOIP_INSTANCE *p_tsoip1 ;
|
||||
p_tsoip1 = (TSOIP_INSTANCE *)malloc(sizeof(TSOIP_INSTANCE));
|
||||
inset_tsoip_instance(p_tsoip1, &ip2ts.tsoip_config_para);
|
||||
MSG msg;
|
||||
msg.type = MSG_IGMP_REINIT;
|
||||
//pmsg->wPara = ; // 具体是web_syspara
|
||||
msg.lPara =(uint32)p_tsoip1;
|
||||
msg.need_free = MSG_NEED_FREE;
|
||||
cttb_msg_send_to_tsoip(&msg);
|
||||
printf("[%s,%d] send msg to TSOIP \n",__FUNCTION__,__LINE__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void load_tsoip_status(TS_NET_STRUCT *p_ts_net, S_TSOIP_LOG_PARA * p_ts_log_param)
|
||||
{
|
||||
//p_ts_net->fpga_tsio_state = p_ts_log_param->tsio_state;
|
||||
}
|
||||
|
||||
|
||||
//定时从FPGA更新信息(如ROW,COL等)
|
||||
static void i2_update_fpga_info(int tsoip_index)
|
||||
{
|
||||
static uint32 tick[2] = {0};
|
||||
uint8 data;
|
||||
uint32 rate;
|
||||
uint32 pkg_num;
|
||||
uint32 ctime;
|
||||
float ip_rate;
|
||||
|
||||
|
||||
// if(!check_delay_over(&tick[tsoip_index], OS_TICKS_PER_SEC))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// printf("[%s,%d]\n", __FUNCTION__,__LINE__);
|
||||
|
||||
// 1 :tsoip1 2:tsoip 2
|
||||
data = tsoip_byte_read(tsoip_index, FPGA_TSIO_STATE);//h20190220
|
||||
if(data == 0xFF)
|
||||
return;
|
||||
|
||||
// if(tsoip_index==TSOIP_2)
|
||||
// printf("TSOIP_%d ,FPGA_TSIO_STATE=0x%x \n", tsoip_index+1, data);
|
||||
|
||||
ip2ts[tsoip_index].tsoip_log_para.tsio_state = data;
|
||||
//printf("TSOIP %d tsio_state=0x%x\n",tsoip_index,data);
|
||||
|
||||
data = tsoip_byte_read(tsoip_index, FPGA_LED_STATUS);
|
||||
if(data == 0xFF)
|
||||
return;
|
||||
ip2ts[tsoip_index].tsoip_log_para.ts_in_flag = (data>>2)&1; //ts in asi_in ok
|
||||
ip2ts[tsoip_index].tsoip_log_para.ts_out_flag = (data>>1)&1; //ts out asi_out ok
|
||||
ip2ts[tsoip_index].tsoip_log_para.ts_err = (data>>0)&1; //ts err
|
||||
ip2ts[tsoip_index].tsoip_log_para.sys_err = 0;
|
||||
|
||||
// rate = tsoip_byte_read(tsoip_index, FPGA_ASI_RATE_HH)<<24; //先读取最高字节,FPGA会锁存低字节
|
||||
// rate|= (tsoip_byte_read(tsoip_index, FPGA_ASI_RATE_HL)<<16)|(tsoip_byte_read(tsoip_index, FPGA_ASI_RATE_LH)<<8)|(tsoip_byte_read(tsoip_index, FPGA_ASI_RATE_LL)<<0);
|
||||
// ip2ts[tsoip_index].tsoip_log_para.ip_out_rate_kbps = rate/1000;
|
||||
|
||||
pkg_num = tsoip_byte_read(tsoip_index, FPGA_IP_PK_NUM_H)<<8;
|
||||
pkg_num |= tsoip_byte_read(tsoip_index, FPGA_IP_PK_NUM_L);
|
||||
|
||||
ctime = tsoip_byte_read(tsoip_index, FPGA_IP_CTIME_H)<<16;
|
||||
ctime |= tsoip_byte_read(tsoip_index, FPGA_IP_CTIME_M)<<8;
|
||||
ctime |= tsoip_byte_read(tsoip_index, FPGA_IP_CTIME_L)<<0;
|
||||
|
||||
//ip_rate = ((double)pkg_num*188*8/((double)ctime*37.037f))*1000000000.0f;
|
||||
//rate=(cpkt*188*8)/(ctime*12.5*1e-9) bit/s
|
||||
ip_rate = (float)pkg_num*1000000*40.608f/(float)ctime; //计算后单位是kbps
|
||||
ip2ts[tsoip_index].tsoip_log_para.asi_out_rate_kbps = (uint32)ip_rate;
|
||||
|
||||
|
||||
if(tsoip_index==TSOIP_1)
|
||||
load_tsoip_status(&ts_net_para, &ip2ts[tsoip_index].tsoip_log_para);
|
||||
|
||||
|
||||
|
||||
//FPGA发送过来的错误标志,是否要重启?
|
||||
if((data >> 3) & 1) {
|
||||
// MSG *pmsg = alloc_msg();
|
||||
// if(pmsg) {
|
||||
// pmsg->type = MSG_SYS_RESET;
|
||||
// send_msg(MAIN_TASK_ID,pmsg);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void i2c_fpga_save_dest_mac(void)
|
||||
{
|
||||
static int sec = 0;
|
||||
|
||||
sec++;
|
||||
if(sec>10)
|
||||
{
|
||||
sec = 0;
|
||||
#if 1
|
||||
fpga_save_dest_mac();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tsoip_init(void)
|
||||
{
|
||||
//memcpy((void*)&i2c_para_bak, &ip2ts.tsoip_config_para, sizeof(S_TSOIP_CONFIG_PARA));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void* tsoip_thr(void * args)
|
||||
{
|
||||
|
||||
int tick_cnt = 0;
|
||||
|
||||
|
||||
//tsoip_init();
|
||||
delay_ms(100);
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"[.thr.] tsoip_thr Start.\n");
|
||||
while(1) {
|
||||
|
||||
if(get_upgrade_flg()){
|
||||
usleep(1000000);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 现在没有 i2C配tsoip模块,i2c自己配
|
||||
//i2c_save_ip2ts_para();
|
||||
|
||||
// 定时从FPGA读状态信息
|
||||
i2_update_fpga_info(TSOIP_1);
|
||||
delay_ms(1000);
|
||||
|
||||
/*if(cttb_para.tsoip_total_num == EMV6_3_TSOIP_NUM){
|
||||
|
||||
i2_update_fpga_info(TSOIP_2);
|
||||
delay_ms(1000);
|
||||
}*/
|
||||
|
||||
tick_cnt += 5;
|
||||
if(tick_cnt > OS_TICKS_PER_SEC) //秒
|
||||
{
|
||||
tick_cnt = 0;
|
||||
//printf("[%s,%d]\n", __FUNCTION__,__LINE__);
|
||||
i2c_fpga_save_dest_mac();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable
+1734
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../inc/upgrade.h"
|
||||
#include "../inc/isys_com.h"
|
||||
|
||||
extern int executeCMD(const char *cmd, char *result, u16 result_size);
|
||||
|
||||
|
||||
|
||||
|
||||
static uint8 gb_upgrade_flg = 0;
|
||||
void set_upgrade_flg(uint8 flg)
|
||||
{
|
||||
gb_upgrade_flg = flg;
|
||||
}
|
||||
|
||||
uint8 get_upgrade_flg(void)
|
||||
{
|
||||
return gb_upgrade_flg;
|
||||
}
|
||||
|
||||
void sys_upgrade(void)
|
||||
{
|
||||
char msg[20] = {0};
|
||||
int ret = 0;
|
||||
int result = 0xff;
|
||||
|
||||
ret = executeCMD(CHECK_UPGRADE_PACKAGE, msg, sizeof(msg));
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"check package return %d , %s\n",ret, msg);
|
||||
for(int j=0;j<20;j++){
|
||||
printf(" 0x%02x", msg[j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(ret==0){
|
||||
result = atoi(msg);
|
||||
//usleep(1000000);
|
||||
if(result == 0){
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"run upgrade sh, and will reboot\n");
|
||||
system(DO_UPGRADE_RUN);
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"system rebooting....\n");
|
||||
// reboot in runme.sh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* imx_up_thr(void * args)
|
||||
{
|
||||
uint8 flg_ok = 0;
|
||||
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"[.thr.] imx_up_thr Start.\n");
|
||||
|
||||
while(1)
|
||||
{
|
||||
flg_ok = get_upgrade_flg();
|
||||
//printf("get flg_ok=%d\n",flg_ok);
|
||||
if(0 != flg_ok) // web upload file ok
|
||||
{
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"------------------------------------------\n");
|
||||
log_printf(LOG_DEBUG,I_NOUSED,"get upgrade flg!!!!!!!!!!!!\n");
|
||||
sys_upgrade();
|
||||
//set_upgrade_flg(0);
|
||||
}
|
||||
usleep(1000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user