Skip to content

Commit

Permalink
Add splint, modified some files to pass checks
Browse files Browse the repository at this point in the history
  • Loading branch information
MDW committed Sep 25, 2023
1 parent 07368e7 commit 96e3701
Show file tree
Hide file tree
Showing 11 changed files with 1,889 additions and 151 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/splint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Splint Check
on: [push, pull_request, workflow_dispatch]
jobs:
analyzer_check_job:
runs-on: ubuntu-22.04
name: Analyze with 'splint'
steps:
- uses: actions/checkout@v4
- name: Install 'splint'
run: |
sudo apt-get update -q && sudo apt install splint
- name: splint analyzer
run: |
./do_splint.sh | tee splint.out
[ ! -s splint.out ]
66 changes: 66 additions & 0 deletions do_splint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash
# When files are provided as arguments, no messages are excluded
FILES="$@"
EXCLUDE_OPTS=""
{
PRJ_DIR=$(realpath $(dirname $(realpath $0)))/
if [ "$FILES" == "" ] ; then
FILES=$(find "${PRJ_DIR}" -type d \( -path "${PRJ_DIR}build" \) -prune -o -name '*.c'|grep -v -E '((tests/.*|src/(am_analyze|abuf|data|data_tag|decoder_util|fileformat|http_server|list|mongoose|optparse|output_file|output_influx|output_log|output_mqtt|output_trigger|output_udp|pulse_analyzer|pulse_data|pulse_detect|pulse_slicer|rfraw|rtl_433|r_api|r_util|samp_grab|sdr|term_ctl|util|write_sigrok|devices/(acurite|acurite_01185m|alecto|ambientweather_tx8300|ambientweather_wh31e|ambient_weather|ant_antplus|archos_tbh|atech_ws308|auriol_4ld5661|auriol_aft77b2|auriol_hg02832|badger_water|baldr_rain|blueline|blyss|brennenstuhl_rcs_2044|bresser_5in1|bresser_6in1|bresser_7in1|bt_rain|burnhardbbq|calibeur|cardin|cavius|ced7000|celsia_czc1|cmr113|companion_wtr001|cotech_36_7959|current_cost|danfoss|digitech_xc0324|directv|dsc|ecodhome|ecowitt|efergy_e2_classic|efergy_optical|efth800|elro_db286a|elv|emax|emos_e6016|emos_e6016_rain|enocean_erp1|ert_idm|esic_emt7110|esperanza_ews|fineoffset|fineoffset_wh1050|fineoffset_wh1080|fineoffset_wh31l|fineoffset_wh45|fineoffset_wn34|fineoffset_ws80|fineoffset_ws90|flex|flowis|fordremote|fs20|ft004b|funkbus|gasmate_ba1008|generic_motion|generic_remote|geo_minim|ge_coloreffects|govee|gt_tmbbq05|gt_wt_02|gt_wt_03|hcs200|hideki|holman_ws5029|hondaremote|honeywell_cm921|ht680|ikea_sparsnas|infactory|inkbird_ith20r|inovalley-kw9015b|insteon|interlogix|intertechno|jasco|kedsum|klimalogg|lacrosse|lacrossews|lacrosse_r1|lacrosse_tx141x|lacrosse_tx31u|lacrosse_tx34|lacrosse_tx35|lacrosse_ws7000|lightwave_rf|markisol|marlec_solar|maverick_et73x|maverick_xr30|megacode|m_bus|neptune_r900|newkaku|nexa|nice_flor_s|norgo|oil_smart|oil_standard|oil_watchman|oil_watchman_advanced|oregon_scientific|oregon_scientific_sl109h|oregon_scientific_v1|philips_aj7010|proflame2|prologue|proove|quhwa|radiohead_ask|rainpoint|regency_fan|revolt_nc5462|rftech|rojaflex|rubicson_48659|rubicson_pool_48942|s3318p|schraeder|scmplus|secplus_v1|secplus_v2|sharp_spc775|simplisafe|simplisafe_gen3|somfy_iohc|somfy_rts|springfield|srsmith_pool_srs_2c_tx|steelmate|telldus_ft0385r|tfa_14_1504_v2|tfa_30_3196|tfa_30_3221|tfa_drop_30.3233|tfa_marbella|tfa_twin_plus_30.3049|thermopro_tp11|thermopro_tx2|thermopro_tx2c|tpms_eezrv|tpms_jansite_solar|tpms_kia|tpms_pmv107j|tpms_porsche|tpms_renault_0435r|tpms_truck|tpms_tyreguard400|ts_ft002|vaillant_vrt340f|vauno_en8822c|wec2103|wg_pb12v1|ws2032|wssensor|x10_rf|yale_hsa)))\.c|build)' )
EXCLUDE_OPTS="
-globs \
+boolint \
+charint \
-exportlocal \
-retvalint \
-noeffect \
-fcnuse \
-compdef \
-usedef \
+skipsysheaders \
+relaxtypes \
-shiftnegative \
-nullinit \
-unrecog \
-globstate \
-paramuse \
-branchstate \
+matchanyintegral \
-mayaliasunique \
-nullassign \
-nullret \
-formatconst \
-nullderef \
-nullpass \
-initallelements \
-fullinitblock \
-bufferoverflowhigh \
-type \
-statictrans \
-nestcomment \
-observertrans \
-immediatetrans \
-mustfreefresh \
-mustfreeonly \
-boolops \
-shiftimplementation
"
fi
splint \
-I"${PRJ_DIR}include" \
+trytorecover \
+forcehints \
+posixstrictlib \
-preproc \
$EXCLUDE_OPTS \
-D__unix__ \
-Drestrict= \
-D_MSC_VER=1300 \
"-Ddata_array_t=int" \
"-Ddata_t=int" \
"-Duint16_t=unsigned short" \
"-Dint16_t=short" \
"-DUINT16_MAX=0xFFFFU" \
"-DSSIZE_T=unsigned long" \
$FILES
} |& tee splint.log

3 changes: 3 additions & 0 deletions include/abuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ void abuf_pop(abuf_t *buf, char *end);

void abuf_cat(abuf_t *buf, const char *str);

#ifndef S_SPLINT_S
int abuf_printf(abuf_t *buf, _Printf_format_string_ char const *restrict format, ...)
#endif

#if defined(__GNUC__) || defined(__clang__)
__attribute__((format(printf, 2, 3)))
#endif
Expand Down
18 changes: 18 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[build-system]
requires = ["setuptools>=61.2"]
build-backend = "setuptools.build_meta"

[project]
dynamic = ["version"]

[tool.codespell]
ignore-words-list = """
stdio,master,ws,hsa,proove,thead,thru,blacklist,wen,ba,fo,uis,slave,clen,te,ans,hass,hist,nd,bu,udo,clas
"""
skip = """./.*,3rdparty,*/.metadata,*.xml,*.qrc"""
quiet-level=2
ignore-regex = '\\[fnrstv]'
builtin = "clear,rare,informal,usage,code,names"

[tool.setuptools]
include-package-data = false
192 changes: 105 additions & 87 deletions src/baseband.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ static uint16_t scaled_squares[256];
/// precalculate lookup table for envelope detection.
static void calc_squares(void)
{
int i;
if (scaled_squares[0])
return; // already initialized
int i;
for (i = 0; i < 256; i++)
scaled_squares[i] = (127 - i) * (127 - i);
}
Expand Down Expand Up @@ -146,6 +146,7 @@ void baseband_low_pass_filter(uint16_t const *x_buf, int16_t *y_buf, uint32_t le
/// [b,a] = butter(1, 0.05) -> 3x tau (95%) ~20 samples
static int const a[FILTER_ORDER + 1] = {FIX(1.00000) >> 1, FIX(0.85408) >> 1};
static int const b[FILTER_ORDER + 1] = {FIX(0.07296) >> 1, FIX(0.07296) >> 1};

// note that coeffs are prescaled by div 2

// Prevent out of bounds access
Expand All @@ -155,8 +156,11 @@ void baseband_low_pass_filter(uint16_t const *x_buf, int16_t *y_buf, uint32_t le

// Calculate first sample
y_buf[0] = (a[1] * state->y[0] + b[0] * (x_buf[0] + state->x[0])) >> (F_SCALE - 1); // note: prescaled, b[0]==b[1]
for (unsigned long i = 1; i < len; i++) {
y_buf[i] = (a[1] * y_buf[i - 1] + b[0] * (x_buf[i] + x_buf[i - 1])) >> (F_SCALE - 1); // note: prescaled, b[0]==b[1]
{
unsigned long i;
for (i = 1; i < len; i++) {
y_buf[i] = (a[1] * y_buf[i - 1] + b[0] * (x_buf[i] + x_buf[i - 1])) >> (F_SCALE - 1); // note: prescaled, b[0]==b[1]
}
}

// Save last samples
Expand Down Expand Up @@ -213,53 +217,60 @@ void baseband_demod_FM(uint8_t const *x_buf, int16_t *y_buf, unsigned long num_s
}
print_logf(LOG_NOTICE, "Baseband", "low pass filter for %u Hz at cutoff %.0f Hz, %.1f us",
samp_rate, samp_rate * low_pass, 1e6 / (samp_rate * low_pass));
{
double ita = 1.0 / tan(M_PI_2 * low_pass);
double gain = 1.0 / (1.0 + ita) / 2; // prescaled by div 2
state->alp_16[0] = FIX(1.0);
state->alp_16[1] = FIX((ita - 1.0) * gain); // scaled by -1
state->blp_16[0] = FIX(gain);
state->blp_16[1] = FIX(gain);
state->rate = samp_rate;
}
}
int32_t const *alp = state->alp_16;
int32_t const *blp = state->blp_16;

// Pre-feed old sample
int16_t x0r = state->xr; // IQ sample: x[n], real
int16_t x0i = state->xi; // IQ sample: x[n], imag
int16_t x0f = state->xf; // Instantaneous frequency
int16_t y0f = state->yf; // Instantaneous frequency, low pass filtered

for (unsigned n = 0; n < num_samples; n++) {
int16_t x1r, x1i; // Old IQ sample: x[n-1]
int16_t x1f, y1f; // Instantaneous frequency, old sample
int32_t pr, pi; // Phase difference vector

// delay old sample
x1r = x0r;
x1i = x0i;
y1f = y0f;
x1f = x0f;
// get new sample
x0r = *x_buf++ - 128;
x0i = *x_buf++ - 128;
// Calculate phase difference vector: x[n] * conj(x[n-1])
pr = x0r * x1r + x0i * x1i; // May exactly overflow an int16_t (-128*-128 + -128*-128)
pi = x0i * x1r - x0r * x1i;
// xlp = (int16_t)((atan2f(pi, pr) / M_PI) * INT16_MAX); // Floating point implementation
x0f = atan2_int16(pi, pr); // Integer implementation
// xlp = pi; // Cheat and use only imaginary part (works OK, but is amplitude sensitive)
// Low pass filter
// y0f = ((alp[1] * y1f >> 1) + (blp[0] * x0f >> 1) + (blp[1] * x1f >> 1)) >> (F_SCALE - 1);
y0f = (alp[1] * y1f + blp[0] * (x0f + x1f)) >> (F_SCALE - 1); // note: prescaled, blp[0]==blp[1]
*y_buf++ = y0f;
}
{
int32_t const *alp = state->alp_16;
int32_t const *blp = state->blp_16;

// Pre-feed old sample
int16_t x0r = state->xr; // IQ sample: x[n], real
int16_t x0i = state->xi; // IQ sample: x[n], imag
int16_t x0f = state->xf; // Instantaneous frequency
int16_t y0f = state->yf; // Instantaneous frequency, low pass filtered

{
unsigned n;
for (n = 0; n < num_samples; n++) {
int16_t x1r, x1i; // Old IQ sample: x[n-1]
int16_t x1f, y1f; // Instantaneous frequency, old sample
int32_t pr, pi; // Phase difference vector

// delay old sample
x1r = x0r;
x1i = x0i;
y1f = y0f;
x1f = x0f;
// get new sample
x0r = *x_buf++ - 128;
x0i = *x_buf++ - 128;
// Calculate phase difference vector: x[n] * conj(x[n-1])
pr = x0r * x1r + x0i * x1i; // May exactly overflow an int16_t (-128*-128 + -128*-128)
pi = x0i * x1r - x0r * x1i;
// xlp = (int16_t)((atan2f(pi, pr) / M_PI) * INT16_MAX); // Floating point implementation
x0f = atan2_int16(pi, pr); // Integer implementation
// xlp = pi; // Cheat and use only imaginary part (works OK, but is amplitude sensitive)
// Low pass filter
// y0f = ((alp[1] * y1f >> 1) + (blp[0] * x0f >> 1) + (blp[1] * x1f >> 1)) >> (F_SCALE - 1);
y0f = (alp[1] * y1f + blp[0] * (x0f + x1f)) >> (F_SCALE - 1); // note: prescaled, blp[0]==blp[1]
*y_buf++ = y0f;
}
}

// Store newest sample for next run
state->xr = x0r;
state->xi = x0i;
state->xf = x0f;
state->yf = y0f;
// Store newest sample for next run
state->xr = x0r;
state->xi = x0i;
state->xf = x0f;
state->yf = y0f;
}
}


Expand Down Expand Up @@ -306,54 +317,61 @@ void baseband_demod_FM_cs16(int16_t const *x_buf, int16_t *y_buf, unsigned long
}
print_logf(LOG_NOTICE, "Baseband", "low pass filter for %u Hz at cutoff %.0f Hz, %.1f us",
samp_rate, samp_rate * low_pass, 1e6 / (samp_rate * low_pass));
double ita = 1.0 / tan(M_PI_2 * low_pass);
double gain = 1.0 / (1.0 + ita);
state->alp_32[0] = FIX32(1.0);
state->alp_32[1] = FIX32((ita - 1.0) * gain); // scaled by -1
state->blp_32[0] = FIX32(gain);
state->blp_32[1] = FIX32(gain);
state->rate = samp_rate;
}
int64_t const *alp = state->alp_32;
int64_t const *blp = state->blp_32;

// Pre-feed old sample
int32_t x0r = state->xr; // IQ sample: x[n], real
int32_t x0i = state->xi; // IQ sample: x[n], imag
int32_t x0f = state->xf; // Instantaneous frequency
int32_t y0f = state->yf; // Instantaneous frequency, low pass filtered

for (unsigned n = 0; n < num_samples; n++) {
int32_t x1r, x1i; // Old IQ sample: x[n-1]
int32_t x1f, y1f; // Instantaneous frequency, old sample
int64_t pr, pi; // Phase difference vector

// delay old sample
x1r = x0r;
x1i = x0i;
y1f = y0f;
x1f = x0f;
// get new sample
x0r = *x_buf++;
x0i = *x_buf++;
// Calculate phase difference vector: x[n] * conj(x[n-1])
pr = (int64_t)x0r * x1r + (int64_t)x0i * x1i; // May exactly overflow an int32_t (-32768*-32768 + -32768*-32768)
pi = (int64_t)x0i * x1r - (int64_t)x0r * x1i;
// xlp = (int32_t)((atan2f(pi, pr) / M_PI) * INT32_MAX); // Floating point implementation
x0f = atan2_int32(pi, pr); // Integer implementation
// xlp = atan2_int16(pi >> 16, pr >> 16) << 16; // Integer implementation, truncated
// xlp = pi; // Cheat and use only imaginary part (works OK, but is amplitude sensitive)
// Low pass filter
// y0f = (alp[1] * y1f + blp[0] * x0f + blp[1] * x1f) >> F_SCALE32;
y0f = (alp[1] * y1f + blp[0] * ((int64_t)x0f + x1f)) >> F_SCALE32; // note: blp[0]==blp[1]
*y_buf++ = y0f >> 16; // not really losing info here, maybe optimize earlier
{
double ita = 1.0 / tan(M_PI_2 * low_pass);
double gain = 1.0 / (1.0 + ita);
state->alp_32[0] = FIX32(1.0);
state->alp_32[1] = FIX32((ita - 1.0) * gain); // scaled by -1
state->blp_32[0] = FIX32(gain);
state->blp_32[1] = FIX32(gain);
state->rate = samp_rate;
}
}
{
int64_t const *alp = state->alp_32;
int64_t const *blp = state->blp_32;

// Pre-feed old sample
int32_t x0r = state->xr; // IQ sample: x[n], real
int32_t x0i = state->xi; // IQ sample: x[n], imag
int32_t x0f = state->xf; // Instantaneous frequency
int32_t y0f = state->yf; // Instantaneous frequency, low pass filtered

{
unsigned n;
for (n = 0; n < num_samples; n++) {
int32_t x1r, x1i; // Old IQ sample: x[n-1]
int32_t x1f, y1f; // Instantaneous frequency, old sample
int64_t pr, pi; // Phase difference vector

// delay old sample
x1r = x0r;
x1i = x0i;
y1f = y0f;
x1f = x0f;
// get new sample
x0r = *x_buf++;
x0i = *x_buf++;
// Calculate phase difference vector: x[n] * conj(x[n-1])
pr = (int64_t)x0r * x1r + (int64_t)x0i * x1i; // May exactly overflow an int32_t (-32768*-32768 + -32768*-32768)
pi = (int64_t)x0i * x1r - (int64_t)x0r * x1i;
// xlp = (int32_t)((atan2f(pi, pr) / M_PI) * INT32_MAX); // Floating point implementation
x0f = atan2_int32(pi, pr); // Integer implementation
// xlp = atan2_int16(pi >> 16, pr >> 16) << 16; // Integer implementation, truncated
// xlp = pi; // Cheat and use only imaginary part (works OK, but is amplitude sensitive)
// Low pass filter
// y0f = (alp[1] * y1f + blp[0] * x0f + blp[1] * x1f) >> F_SCALE32;
y0f = (alp[1] * y1f + blp[0] * ((int64_t)x0f + x1f)) >> F_SCALE32; // note: blp[0]==blp[1]
*y_buf++ = y0f >> 16; // not really losing info here, maybe optimize earlier
}
}

// Store newest sample for next run
state->xr = x0r;
state->xi = x0i;
state->xf = x0f;
state->yf = y0f;
// Store newest sample for next run
state->xr = x0r;
state->xi = x0i;
state->xf = x0f;
state->yf = y0f;
}
}

void baseband_init(void)
Expand Down
Loading

0 comments on commit 96e3701

Please sign in to comment.