提交SMOD ATSC IMX APP版本 V122

This commit is contained in:
2026-07-16 14:35:59 +08:00
commit 7601c270d5
485 changed files with 255032 additions and 0 deletions
+187
View File
@@ -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;
}
+1275
View File
File diff suppressed because it is too large Load Diff
+1690
View File
File diff suppressed because it is too large Load Diff
+1624
View File
File diff suppressed because it is too large Load Diff
+51
View File
@@ -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
+492
View File
@@ -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;
}
+719
View File
@@ -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));
}
+2352
View File
File diff suppressed because it is too large Load Diff
+2436
View File
File diff suppressed because it is too large Load Diff
+15126
View File
File diff suppressed because it is too large Load Diff
+619
View File
@@ -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
+112
View File
@@ -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
+129
View File
@@ -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);
}
}
+234
View File
@@ -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
+708
View File
@@ -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
+311
View File
@@ -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();
}
}
}
+1734
View File
File diff suppressed because it is too large Load Diff
+71
View File
@@ -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