demod -a

加载内核模块
The driver should have come with an installer script, that copies the
module to the correct directory your runtime kernel is using for
modules.  If the driver download is nothing but a .ko file, do you
know what kernel it was complied for?  try sticking it in
/lib/modules/$YOUR_KERNEL_VERSION/extra and then do a depmod -a to
update the modules list, and lastly a modprobe to load your module.
multimon-ng是一个可以解码pocsag的程序,我想修改一下,让他可以解码一段pocasg数据中有两个地址码的,比如2025-11-23 11:08:12: POCSAG1200: Address: 1234001 Function: 1 Numeric: 123456 2025-11-23 11:08:12: POCSAG1200: Address: 1234003 Function: 1 Numeric: 20201411111112121212121542124121212这是收到的消息,这两条应该是一条信息,因为第一条放不下,所以变成了两条,但是解码会把他分开解码,这是multimon-ng的代码 /* * pocsag.c -- POCSAG protocol decoder * * Copyright (C) 1996 * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) * * Copyright (C) 2012-2014 * Elias Oenal (multimon-ng@eliasoenal.com) * * Copyright (C) 2022 * Tobias Girstmair (https://gir.st/) * * Copyright (C) 2024 * Jason Lingohr (jason@lucid.net.au) * * POCSAG (Post Office Code Standard Advisory Group) * Radio Paging Decoder * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ---------------------------------------------------------------------- */ #include "multimon.h" #include <string.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "cJSON.h" /* ---------------------------------------------------------------------- */ //#define CHARSET_LATIN1 //#define CHARSET_UTF8 //ÄÖÜäöüß /* ---------------------------------------------------------------------- */ /* * some codewords with special POCSAG meaning */ #define POCSAG_SYNC 0x7cd215d8 #define POCSAG_IDLE 0x7a89c197 #define POCSAG_SYNCINFO 0x7cf21436 // what is this value? #define POCSAG_SYNC_WORDS ((2000000 >> 3) << 13) #define POCSAG_MESSAGE_DETECTION 0x80000000 // Most significant bit is a one #define CAESAR_ALPHA 0 #define CAESAR_SKYPER 1 // skyper messages are ROT-1 enciphered #define POSCAG /* ---------------------------------------------------------------------- */ int pocsag_mode = POCSAG_MODE_STANDARD; int pocsag_invert_input = 0; int pocsag_error_correction = 2; int pocsag_show_partial_decodes = 0; int pocsag_heuristic_pruning = 0; int pocsag_prune_empty = 0; extern int json_mode; /* ---------------------------------------------------------------------- */ enum states{ NO_SYNC = 0, //0b00000000 SYNC = 64, //0b10000000 LOSING_SYNC = 65, //0b10000001 LOST_SYNC = 66, //0b10000010 ADDRESS = 67, //0b10000011 MESSAGE = 68, //0b10000100 END_OF_MESSAGE = 69, //0b10000101 }; static inline unsigned char even_parity(uint32_t data) { unsigned int temp = data ^ (data >> 16); temp = temp ^ (temp >> 8); temp = temp ^ (temp >> 4); temp = temp ^ (temp >> 2); temp = temp ^ (temp >> 1); return temp & 1; } /* ---------------------------------------------------------------------- */ /* * the code used by POCSAG is a (n=31,k=21) BCH Code with dmin=5, * thus it could correct two bit errors in a 31-Bit codeword. * It is a systematic code. * The generator polynomial is: * g(x) = x^10+x^9+x^8+x^6+x^5+x^3+1 * The parity check polynomial is: * h(x) = x^21+x^20+x^18+x^16+x^14+x^13+x^12+x^11+x^8+x^5+x^3+1 * g(x) * h(x) = x^n+1 */ #define BCH_POLY 03551 /* octal */ #define BCH_N 31 #define BCH_K 21 /* ---------------------------------------------------------------------- */ static unsigned int pocsag_syndrome(uint32_t data) { uint32_t shreg = data >> 1; /* throw away parity bit */ uint32_t mask = 1L << (BCH_N-1), coeff = BCH_POLY << (BCH_K-1); int n = BCH_K; for(; n > 0; mask >>= 1, coeff >>= 1, n--) if (shreg & mask) shreg ^= coeff; if (even_parity(data)) shreg |= (1 << (BCH_N - BCH_K)); verbprintf(9, "BCH syndrome: data: %08lx syn: %08lx\n", data, shreg); return shreg; } /* ---------------------------------------------------------------------- */ // ISO 646 national variant: US / IRV (1991) char *trtab[128] = { "<NUL>", // 0x0 "<SOH>", // 0x1 "<STX>", // 0x2 "<ETX>", // 0x3 "<EOT>", // 0x4 "<ENQ>", // 0x5 "<ACK>", // 0x6 "<BEL>", // 0x7 "<BS>", // 0x8 "<HT>", // 0x9 "<LF>", // 0xa "<VT>", // 0xb "<FF>", // 0xc "<CR>", // 0xd "<SO>", // 0xe "<SI>", // 0xf "<DLE>", // 0x10 "<DC1>", // 0x11 "<DC2>", // 0x12 "<DC3>", // 0x13 "<DC4>", // 0x14 "<NAK>", // 0x15 "<SYN>", // 0x16 "<ETB>", // 0x17 "<CAN>", // 0x18 "<EM>", // 0x19 "<SUB>", // 0x1a "<ESC>", // 0x1b "<FS>", // 0x1c "<GS>", // 0x1d "<RS>", // 0x1e "<US>", // 0x1f " ", // 0x20 "!", // 0x21 "\"", // 0x22 // national variant "#", // 0x23 "$", // 0x24 "%", // 0x25 "&", // 0x26 "'", // 0x27 "(", // 0x28 ")", // 0x29 "*", // 0x2a "+", // 0x2b ",", // 0x2c "-", // 0x2d ".", // 0x2e "/", // 0x2f "0", // 0x30 "1", // 0x31 "2", // 0x32 "3", // 0x33 "4", // 0x34 "5", // 0x35 "6", // 0x36 "7", // 0x37 "8", // 0x38 "9", // 0x39 ":", // 0x3a ";", // 0x3b "<", // 0x3c "=", // 0x3d ">", // 0x3e "?", // 0x3f "@", // 0x40 "A", // 0x41 "B", // 0x42 "C", // 0x43 "D", // 0x44 "E", // 0x45 "F", // 0x46 "G", // 0x47 "H", // 0x48 "I", // 0x49 "J", // 0x4a "K", // 0x4b "L", // 0x4c "M", // 0x4d "N", // 0x4e "O", // 0x4f "P", // 0x50 "Q", // 0x51 "R", // 0x52 "S", // 0x53 "T", // 0x54 "U", // 0x55 "V", // 0x56 "W", // 0x57 "X", // 0x58 "Y", // 0x59 "Z", // 0x5a // national variant "[", // 0x5b "\\", // 0x5c "]", // 0x5d "^", // 0x5e "_", // 0x5f // national variant "`", // 0x60 "a", // 0x61 "b", // 0x62 "c", // 0x63 "d", // 0x64 "e", // 0x65 "f", // 0x66 "g", // 0x67 "h", // 0x68 "i", // 0x69 "j", // 0x6a "k", // 0x6b "l", // 0x6c "m", // 0x6d "n", // 0x6e "o", // 0x6f "p", // 0x70 "q", // 0x71 "r", // 0x72 "s", // 0x73 "t", // 0x74 "u", // 0x75 "v", // 0x76 "w", // 0x77 "x", // 0x78 "y", // 0x79 "z", // 0x7a // national variant "{", // 0x7b "|", // 0x7c "}", // 0x7d "~", // 0x7e "<DEL>" // 0x7f }; /* // national variant "#", // 0x23 "$", // 0x24 "[", // 0x5b "\\", // 0x5c "]", // 0x5d "^", // 0x5e "`", // 0x60 "{", // 0x7b "|", // 0x7c "}", // 0x7d "~", // 0x7e */ bool pocsag_init_charset(char *charset) { if(strcmp(charset,"DE")==0) // German charset { #ifdef CHARSET_UTF8 trtab[0x5b] = "Ä"; trtab[0x5c] = "Ö"; trtab[0x5d] = "Ü"; trtab[0x7b] = "ä"; trtab[0x7c] = "ö"; trtab[0x7d] = "ü"; trtab[0x7e] = "ß"; #elif defined CHARSET_LATIN1 trtab[0x5b] = "\304"; trtab[0x5c] = "\326"; trtab[0x5d] = "\334"; trtab[0x7b] = "\344"; trtab[0x7c] = "\366"; trtab[0x7d] = "\374"; trtab[0x7e] = "\337"; #else trtab[0x5b] = "AE"; trtab[0x5c] = "OE"; trtab[0x5d] = "UE"; trtab[0x7b] = "ae"; trtab[0x7c] = "oe"; trtab[0x7d] = "ue"; trtab[0x7e] = "ss"; #endif } else if (strcmp(charset,"DK")==0) // Danish charset /JT Ref. https://www.ascii-code.com { #ifdef CHARSET_UTF8 trtab[0x5b] = "Æ"; trtab[0x5c] = "Ø"; trtab[0x5d] = "Å"; trtab[0x7b] = "æ"; trtab[0x7c] = "ø"; trtab[0x7d] = "å"; #elif defined CHARSET_LATIN1 trtab[0x5b] = "\306"; trtab[0x5c] = "\330"; trtab[0x5d] = "\305"; trtab[0x7b] = "\346"; trtab[0x7c] = "\370"; trtab[0x7d] = "\345"; #else trtab[0x5b] = "AE"; trtab[0x5c] = "OE"; trtab[0x5d] = "Aa"; trtab[0x7b] = "ae"; trtab[0x7c] = "oe"; trtab[0x7d] = "aa"; #endif } else if (strcmp(charset,"SE")==0) // Swedish charset { #ifdef CHARSET_UTF8 trtab[0x5b] = "Ä"; trtab[0x5c] = "Ö"; trtab[0x5d] = "Å"; trtab[0x7b] = "ä"; trtab[0x7c] = "ö"; trtab[0x7d] = "å"; #elif defined CHARSET_LATIN1 trtab[0x5b] = "\304"; trtab[0x5c] = "\326"; trtab[0x5d] = "\305"; trtab[0x7b] = "\344"; trtab[0x7c] = "\366"; trtab[0x7d] = "\345"; #else trtab[0x5b] = "AE"; trtab[0x5c] = "OE"; trtab[0x5d] = "AO"; trtab[0x7b] = "ae"; trtab[0x7c] = "oe"; trtab[0x7d] = "ao"; #endif } else if (strcmp(charset,"FR")==0) // French charset { trtab[0x24] = "£"; trtab[0x40] = "à"; trtab[0x5b] = "°"; trtab[0x5c] = "ç"; trtab[0x5d] = "§"; trtab[0x5e] = "^"; trtab[0x5f] = "_"; trtab[0x60] = "µ"; trtab[0x7b] = "é"; trtab[0x7c] = "ù"; trtab[0x7d] = "è"; trtab[0x7e] = "¨"; } else if (strcmp(charset,"SI")==0) // Slovenian charset { trtab[0x40] = "Ž"; trtab[0x5b] = "Š"; trtab[0x5d] = "Ć"; trtab[0x5e] = "Č"; trtab[0x60] = "ž"; trtab[0x7b] = "š"; trtab[0x7d] = "ć"; trtab[0x7e] = "č"; } else if (strcmp(charset,"US")==0) // US charset { // default } else { fprintf(stderr, "Error: invalid POCSAG charset %s\n", charset); fprintf(stderr, "Use: US,FR,DE,DK,SE,SI\n"); charset = "US"; return false; } return true; } static char *translate_alpha(unsigned char chr) { return trtab[chr & 0x7f]; } /* ---------------------------------------------------------------------- */ static int guesstimate_alpha(const unsigned char cp) { if((cp > 0 && cp < 32) || cp == 127) return -5; // Non printable characters are uncommon else if((cp > 32 && cp < 48) || (cp > 57 && cp < 65) || (cp > 90 && cp < 97) || (cp > 122 && cp < 127)) return -2; // Penalize special characters else return 1; } static int guesstimate_numeric(const unsigned char cp, int pos) { if(cp == 'U') return -10; else if(cp == '[' || cp == ']') return -5; else if(cp == ' ' || cp == '.' || cp == '-') return -2; else if(pos < 10) // Penalize long messages return 5; else return 0; } static int print_msg_numeric(struct l2_state_pocsag *rx, char* buff, unsigned int size) { static const char *conv_table = "084 2.6]195-3U7["; unsigned char *bp = rx->buffer; int len = rx->numnibbles; char* cp = buff; int guesstimate = 0; if ( (unsigned int) len >= size) len = size-1; for (; len > 0; bp++, len -= 2) { *cp++ = conv_table[(*bp >> 4) & 0xf]; if (len > 1) *cp++ = conv_table[*bp & 0xf]; } *cp = '\0'; cp = buff; for(int i = 0; *(cp+i); i++) guesstimate += guesstimate_numeric(*(cp+i), i); return guesstimate; } static unsigned char get7(const unsigned char *buf, int n) { /* returns the n-th seven bit word */ return ( buf[(n*7)/8]<<8 | buf[(n*7+6)/8] ) >> (n+1)%8; } static unsigned char rev7(unsigned char b) { /* reverses the bit order of a seven bit word */ return ((b << 6) & 64) | ((b >> 6) & 1) | ((b << 4) & 32) | ((b >> 4) & 2) | ((b << 2) & 16) | ((b >> 2) & 4) | ((b << 0) & 8); } static int print_msg_alpha(struct l2_state_pocsag *rx, char* buff, unsigned int size, int caesar) { int len = rx->numnibbles * 4 / 7; char* cp = buff; int buffree = size-1; unsigned char curchr; char *tstr; int guesstimate = 0; for (int i = 0; i < len; i++) { curchr = rev7(get7(rx->buffer, i)) - caesar; guesstimate += guesstimate_alpha(curchr); tstr = translate_alpha(curchr); if (tstr) { int tlen = strlen(tstr); if (buffree >= tlen) { memcpy(cp, tstr, tlen); cp += tlen; buffree -= tlen; } } else if (buffree > 0) { *cp++ = curchr; buffree--; } } *cp = '\0'; return guesstimate; } /* ---------------------------------------------------------------------- */ static void pocsag_printmessage(struct demod_state *s, bool sync) { if(!pocsag_show_partial_decodes && ((s->l2.pocsag.address == -2) || (s->l2.pocsag.function == -2) || !sync)) return; // Hide partial decodes if(pocsag_prune_empty && (s->l2.pocsag.numnibbles == 0)) return; cJSON *json_output = cJSON_CreateObject(); if((s->l2.pocsag.address != -1) || (s->l2.pocsag.function != -1)) { if(s->l2.pocsag.numnibbles == 0) { if (!json_mode) { verbprintf(0, "%s: Address: %7lu Function: %1hhi ",s->dem_par->name, s->l2.pocsag.address, s->l2.pocsag.function); if(!sync) verbprintf(2,"<LOST SYNC>"); verbprintf(0,"\n"); } else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNumberToObject(json_output, "address", s->l2.pocsag.address); cJSON_AddNumberToObject(json_output, "function", s->l2.pocsag.function); fprintf(stdout, "%s\n", cJSON_PrintUnformatted(json_output)); cJSON_Delete(json_output); } } else { char num_string[1024]; char alpha_string[1024]; char skyper_string[1024]; int guess_num = 0; int guess_alpha = 0; int guess_skyper = 0; int unsure = 0; int func = 0; guess_num = print_msg_numeric(&s->l2.pocsag, num_string, sizeof(num_string)); guess_alpha = print_msg_alpha(&s->l2.pocsag, alpha_string, sizeof(alpha_string), CAESAR_ALPHA); guess_skyper = print_msg_alpha(&s->l2.pocsag, skyper_string, sizeof(skyper_string), CAESAR_SKYPER); func = s->l2.pocsag.function; if(guess_num < 20 && guess_alpha < 20 && guess_skyper < 20) { if(pocsag_heuristic_pruning) return; unsure = 1; } if((pocsag_mode == POCSAG_MODE_NUMERIC) || ((pocsag_mode == POCSAG_MODE_STANDARD) && (func == 0)) || ((pocsag_mode == POCSAG_MODE_AUTO) && (guess_num >= 20 || unsure))) { if((s->l2.pocsag.address != -2) || (s->l2.pocsag.function != -2)) { if (!json_mode) verbprintf(0, "%s: Address: %7lu Function: %1hhi ",s->dem_par->name, s->l2.pocsag.address, s->l2.pocsag.function); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNumberToObject(json_output, "address", s->l2.pocsag.address); cJSON_AddNumberToObject(json_output, "function", s->l2.pocsag.function); } } else { if (!json_mode) verbprintf(0, "%s: Address: - Function: - ",s->dem_par->name); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNullToObject(json_output, "address"); cJSON_AddNullToObject(json_output, "function"); } } if(pocsag_mode == POCSAG_MODE_AUTO) verbprintf(3, "Certainty: %5i ", guess_num); if (!json_mode) { verbprintf(0, "Numeric: %s", num_string); if(!sync) verbprintf(2,"<LOST SYNC>"); verbprintf(0,"\n"); } else { cJSON_AddStringToObject(json_output, "numeric", num_string); fprintf(stdout, "%s\n", cJSON_PrintUnformatted(json_output)); fflush(stdout); cJSON_Delete(json_output); } } if((pocsag_mode == POCSAG_MODE_ALPHA) || ((pocsag_mode == POCSAG_MODE_STANDARD) && (func != 0)) || ((pocsag_mode == POCSAG_MODE_AUTO) && (guess_alpha >= guess_skyper || unsure))) { if((s->l2.pocsag.address != -2) || (s->l2.pocsag.function != -2)) { if (!json_mode) verbprintf(0, "%s: Address: %7lu Function: %1hhi ",s->dem_par->name, s->l2.pocsag.address, s->l2.pocsag.function); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNumberToObject(json_output, "address", s->l2.pocsag.address); cJSON_AddNumberToObject(json_output, "function", s->l2.pocsag.function); } } else { if (!json_mode) verbprintf(0, "%s: Address: - Function: - ",s->dem_par->name); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNullToObject(json_output, "address"); cJSON_AddNullToObject(json_output, "function"); } } if(pocsag_mode == POCSAG_MODE_AUTO) verbprintf(3, "Certainty: %5i ", guess_alpha); if (!json_mode) { verbprintf(0, "Alpha: %s", alpha_string); if(!sync) verbprintf(2,"<LOST SYNC>"); verbprintf(0,"\n"); } else { cJSON_AddStringToObject(json_output, "alpha", alpha_string); fprintf(stdout, "%s\n", cJSON_PrintUnformatted(json_output)); fflush(stdout); cJSON_Delete(json_output); } } if((pocsag_mode == POCSAG_MODE_SKYPER) || ((pocsag_mode == POCSAG_MODE_AUTO) && (guess_skyper >= guess_alpha || unsure))) // Only output SKYPER if we're explicitly asking for it or we're auto guessing! (because it's not part of one of the standards, right?!) { if((s->l2.pocsag.address != -2) || (s->l2.pocsag.function != -2)) if (!json_mode) verbprintf(0, "%s: Address: %7lu Function: %1hhi ",s->dem_par->name, s->l2.pocsag.address, s->l2.pocsag.function); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNumberToObject(json_output, "address", s->l2.pocsag.address); cJSON_AddNumberToObject(json_output, "function", s->l2.pocsag.function); } else if (!json_mode) verbprintf(0, "%s: Address: - Function: - ",s->dem_par->name); else { cJSON_AddStringToObject(json_output, "demod_name", s->dem_par->name); cJSON_AddNullToObject(json_output, "address"); cJSON_AddNullToObject(json_output, "function"); } if(pocsag_mode == POCSAG_MODE_AUTO) verbprintf(3, "Certainty: %5i ", guess_skyper); if (!json_mode) { verbprintf(0, "Skyper: %s", skyper_string); if(!sync) verbprintf(2,"<LOST SYNC>"); verbprintf(0,"\n"); } else { cJSON_AddStringToObject(json_output, "skyper", skyper_string); fprintf(stdout, "%s\n", cJSON_PrintUnformatted(json_output)); fflush(stdout); cJSON_Delete(json_output); } } } } } /* ---------------------------------------------------------------------- */ void pocsag_init(struct demod_state *s) { memset(&s->l2.pocsag, 0, sizeof(s->l2.pocsag)); s->l2.pocsag.address = -1; s->l2.pocsag.function = -1; } void pocsag_deinit(struct demod_state *s) { if(s->l2.pocsag.pocsag_total_error_count) verbprintf(1, "\n===%s stats===\n" "Words BCH checked: %u\n" "Corrected errors: %u\n" "Corrected 1bit errors: %u\n" "Corrected 2bit errors: %u\n" "Invalid word or >2 bits errors: %u\n\n" "Total bits processed: %u\n" "Bits processed while in sync: %u\n" "Bits processed while out of sync: %u\n" "Successfully decoded: %f%%\n", s->dem_par->name, s->l2.pocsag.pocsag_total_error_count, s->l2.pocsag.pocsag_corrected_error_count, s->l2.pocsag.pocsag_corrected_1bit_error_count, s->l2.pocsag.pocsag_corrected_2bit_error_count, s->l2.pocsag.pocsag_uncorrected_error_count, s->l2.pocsag.pocsag_total_bits_received, s->l2.pocsag.pocsag_bits_processed_while_synced, s->l2.pocsag.pocsag_bits_processed_while_not_synced, (100./s->l2.pocsag.pocsag_total_bits_received)*s->l2.pocsag.pocsag_bits_processed_while_synced); fflush(stdout); } static uint32_t transpose_n(int n, uint32_t *matrix) { uint32_t out = 0; int j; for (j = 0; j < 32; ++j) { if (matrix[j] & (1<<n)) out |= (1<<j); } return out; } #define ONE 0xffffffff static uint32_t * transpose_clone(uint32_t src, uint32_t *out) { int i; if (!out) out = malloc(sizeof(uint32_t)*32); for (i = 0; i < 32; ++i) { if (src & (1<<i)) out[i] = ONE; else out[i] = 0; } return out; } static void bitslice_syndrome(uint32_t *slices) { const int firstBit = BCH_N - 1; int i, n; uint32_t paritymask = slices[0]; // do the parity and shift together for (i = 1; i < 32; ++i) { paritymask ^= slices[i]; slices[i-1] = slices[i]; } slices[31] = 0; // BCH_POLY << (BCH_K - 1) is // 20 21 22 23 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ONE, 0, 0, ONE, // 24 25 26 27 28 29 30 31 // 0, ONE, ONE, 0, ONE, ONE, ONE, 0 for (n = 0; n < BCH_K; ++n) { // one line here for every '1' bit in coeff (above) const int bit = firstBit - n; slices[20 - n] ^= slices[bit]; slices[23 - n] ^= slices[bit]; slices[25 - n] ^= slices[bit]; slices[26 - n] ^= slices[bit]; slices[28 - n] ^= slices[bit]; slices[29 - n] ^= slices[bit]; slices[30 - n] ^= slices[bit]; slices[31 - n] ^= slices[bit]; } // apply the parity mask we built up slices[BCH_N - BCH_K] |= paritymask; } /* ---------------------------------------------------------------------- */ // This might not be elegant, yet effective! // Error correction via bruteforce ;) // // It's a pragmatic solution since this was much faster to implement // than understanding the math to solve it while being as effective. // Besides that the overhead is neglectable. int pocsag_brute_repair(struct l2_state_pocsag *rx, uint32_t* data) { if (pocsag_syndrome(*data)) { rx->pocsag_total_error_count++; verbprintf(6, "Error in syndrome detected!\n"); } else { return 0; } if(pocsag_error_correction == 0) { rx->pocsag_uncorrected_error_count++; verbprintf(6, "Couldn't correct error!\n"); return 1; } // check for single bit errors { int i, n, b1, b2; uint32_t res; uint32_t *xpose = 0, *in = 0; xpose = malloc(sizeof(uint32_t)*32); in = malloc(sizeof(uint32_t)*32); transpose_clone(*data, xpose); for (i = 0; i < 32; ++i) xpose[i] ^= (1<<i); bitslice_syndrome(xpose); res = 0; for (i = 0; i < 32; ++i) res |= xpose[i]; res = ~res; if (res) { int n = 0; while (res) { ++n; res >>= 1; } --n; *data ^= (1<<n); rx->pocsag_corrected_error_count++; rx->pocsag_corrected_1bit_error_count++; goto returnfree; } if(pocsag_error_correction == 1) { rx->pocsag_uncorrected_error_count++; verbprintf(6, "Couldn't correct error!\n"); if (xpose) free(xpose); if (in) free(in); return 1; } //check for two bit errors n = 0; transpose_clone(*data, xpose); for (b1 = 0; b1 < 32; ++b1) { for (b2 = b1; b2 < 32; ++b2) { xpose[b1] ^= (1<<n); xpose[b2] ^= (1<<n); if (++n == 32) { memcpy(in, xpose, sizeof(uint32_t)*32); bitslice_syndrome(xpose); res = 0; for (i = 0; i < 32; ++i) res |= xpose[i]; res = ~res; if (res) { int n = 0; while (res) { ++n; res >>= 1; } --n; *data = transpose_n(n, in); rx->pocsag_corrected_error_count++; rx->pocsag_corrected_2bit_error_count++; goto returnfree; } transpose_clone(*data, xpose); n = 0; } } } if (n > 0) { memcpy(in, xpose, sizeof(uint32_t)*32); bitslice_syndrome(xpose); res = 0; for (i = 0; i < 32; ++i) res |= xpose[i]; res = ~res; if (res) { int n = 0; while (res) { ++n; res >>= 1; } --n; *data = transpose_n(n, in); rx->pocsag_corrected_error_count++; rx->pocsag_corrected_2bit_error_count++; goto returnfree; } } rx->pocsag_uncorrected_error_count++; verbprintf(6, "Couldn't correct error!\n"); if (xpose) free(xpose); if (in) free(in); return 1; returnfree: if (xpose) free(xpose); if (in) free(in); return 0; } } static inline bool word_complete(struct demod_state *s) { // Do nothing for 31 bits // When the word is complete let the program counter pass s->l2.pocsag.rx_bit = (s->l2.pocsag.rx_bit + 1) % 32; return s->l2.pocsag.rx_bit == 0; } static inline bool is_sync(const uint32_t * const rx_data) { if(*rx_data == POCSAG_SYNC) return true; // Sync found! return false; } static inline bool is_idle(const uint32_t * const rx_data) { if(*rx_data == POCSAG_IDLE) return true; // Idle found! return false; } static void do_one_bit(struct demod_state *s, uint32_t rx_data) { s->l2.pocsag.pocsag_total_bits_received++; switch(s->l2.pocsag.state & SYNC) { case NO_SYNC: { s->l2.pocsag.pocsag_bits_processed_while_not_synced++; pocsag_brute_repair(&s->l2.pocsag, &rx_data); if(is_sync(&rx_data)) { verbprintf(4, "Aquired sync!\n"); s->l2.pocsag.state = SYNC; } return; } case SYNC: { s->l2.pocsag.pocsag_bits_processed_while_synced++; if(!word_complete(s)) return; // Wait for more bits to arrive. // it is always 17 words unsigned char rxword = s->l2.pocsag.rx_word; // for address calculation s->l2.pocsag.rx_word = (s->l2.pocsag.rx_word + 1) % 17; if(s->l2.pocsag.state == SYNC) s->l2.pocsag.state = ADDRESS; // We're in sync, move on. if(pocsag_brute_repair(&s->l2.pocsag, &rx_data)) { // Arbitration lost if(s->l2.pocsag.state != LOST_SYNC) s->l2.pocsag.state = LOSING_SYNC; } else { if(s->l2.pocsag.state == LOST_SYNC) { verbprintf(4, "Recovered sync!\n"); s->l2.pocsag.state = ADDRESS; } } if(is_sync(&rx_data)) return; // Already sync'ed. while(true) switch(s->l2.pocsag.state) { case LOSING_SYNC: { verbprintf(4, "Losing sync!\n"); // Output what we've received so far. pocsag_printmessage(s, false); s->l2.pocsag.numnibbles = 0; s->l2.pocsag.address = -1; s->l2.pocsag.function = -1; s->l2.pocsag.state = LOST_SYNC; return; } case LOST_SYNC: { verbprintf(4, "Lost sync!\n"); s->l2.pocsag.state = NO_SYNC; s->l2.pocsag.rx_word = 0; return; } case ADDRESS: { if(is_idle(&rx_data)) // Idle codewords have a magic address return; if(rx_data & POCSAG_MESSAGE_DETECTION) { verbprintf(4, "Got a message: %u\n", rx_data); s->l2.pocsag.function = -2; s->l2.pocsag.address = -2; s->l2.pocsag.state = MESSAGE; break; // Performing partial decode } verbprintf(4, "Got an address: %u\n", rx_data); s->l2.pocsag.function = (rx_data >> 11) & 3; s->l2.pocsag.address = ((rx_data >> 10) & 0x1ffff8) | ((rxword >> 1) & 7); s->l2.pocsag.state = MESSAGE; return; } case MESSAGE: { if(rx_data & POCSAG_MESSAGE_DETECTION) verbprintf(4, "Got a message: %u\n", rx_data); else { // Address/idle signals end of message verbprintf(4, "Got an address: %u\n", rx_data); s->l2.pocsag.state = END_OF_MESSAGE; break; } if (s->l2.pocsag.numnibbles > sizeof(s->l2.pocsag.buffer)*2 - 5) { if (!json_mode) { verbprintf(0, "%s: Warning: Message too long\n", s->dem_par->name); } else { fprintf(stdout, "{\"error\": \"%s: Warning: Message too long\n\"}", s->dem_par->name); fflush(stdout); } s->l2.pocsag.state = END_OF_MESSAGE; break; } uint32_t data; unsigned char *bp; bp = s->l2.pocsag.buffer + (s->l2.pocsag.numnibbles >> 1); data = (rx_data >> 11); if (s->l2.pocsag.numnibbles & 1) { bp[0] = (bp[0] & 0xf0) | ((data >> 16) & 0xf); bp[1] = data >> 8; bp[2] = data; } else { bp[0] = data >> 12; bp[1] = data >> 4; bp[2] = data << 4; } s->l2.pocsag.numnibbles += 5; verbprintf(5, "We received something!\n"); return; } case END_OF_MESSAGE: { verbprintf(4, "End of message!\n"); pocsag_printmessage(s, true); s->l2.pocsag.numnibbles = 0; s->l2.pocsag.address = -1; s->l2.pocsag.function = -1; s->l2.pocsag.state = ADDRESS; break; } default: break; } } default: break; } } /* ---------------------------------------------------------------------- */ void pocsag_rxbit(struct demod_state *s, int32_t bit) { s->l2.pocsag.rx_data <<= 1; s->l2.pocsag.rx_data |= !bit; verbprintf(9, " %c ", '1'-(s->l2.pocsag.rx_data & 1)); if(pocsag_invert_input) do_one_bit(s, ~(s->l2.pocsag.rx_data)); // this tries the inverted signal else do_one_bit(s, s->l2.pocsag.rx_data); } /* ---------------------------------------------------------------------- */ /* * demod_poc12.c -- 1200 baud POCSAG demodulator * * Copyright (C) 1996 * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) * Copyright (C) 2024 * Marat Fayzullin (luarvique@gmail.com) * * POCSAG (Post Office Code Standard Advisory Group) * Radio Paging Decoder * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ---------------------------------------------------------------------- */ #include "multimon.h" #include "filter.h" #include <math.h> #include <string.h> #include <stdio.h> /* ---------------------------------------------------------------------- */ #define FREQ_SAMP 22050 #define BAUD 1200 #define SUBSAMP 2 #define FILTLEN 1 /* ---------------------------------------------------------------------- */ #define SPHASEINC (0x10000u*BAUD*SUBSAMP/FREQ_SAMP) /* ---------------------------------------------------------------------- */ static void poc12_init(struct demod_state *s) { pocsag_init(s); memset(&s->l1.poc12, 0, sizeof(s->l1.poc12)); } /* ---------------------------------------------------------------------- */ static void poc12_demod(struct demod_state *s, buffer_t buffer, int length) { if (s->l1.poc12.subsamp) { if (length <= (int)s->l1.poc12.subsamp) { s->l1.poc12.subsamp -= length; return; } buffer.fbuffer += s->l1.poc12.subsamp; length -= s->l1.poc12.subsamp; s->l1.poc12.subsamp = 0; } for (; length > 0; length -= SUBSAMP, buffer.fbuffer += SUBSAMP) { s->l1.poc12.dcd_shreg <<= 1; s->l1.poc12.dcd_shreg |= ((*buffer.fbuffer) > 0); verbprintf(10, "%c", '0'+(s->l1.poc12.dcd_shreg & 1)); /* * check if transition */ if ((s->l1.poc12.dcd_shreg ^ (s->l1.poc12.dcd_shreg >> 1)) & 1) { if (s->l1.poc12.sphase < (0x8000u-(SPHASEINC/2))) s->l1.poc12.sphase += SPHASEINC/8; else s->l1.poc12.sphase -= SPHASEINC/8; } s->l1.poc12.sphase += SPHASEINC; if (s->l1.poc12.sphase >= 0x10000u) { s->l1.poc12.sphase &= 0xffffu; pocsag_rxbit(s, s->l1.poc12.dcd_shreg & 1); } } s->l1.poc12.subsamp = -length; } static void poc12_deinit(struct demod_state *s) { pocsag_deinit(s); } /* ---------------------------------------------------------------------- */ const struct demod_param demod_poc12 = { "POCSAG1200", true, FREQ_SAMP, FILTLEN, poc12_init, poc12_demod, poc12_deinit }; /* ---------------------------------------------------------------------- */ /* * multimon.h -- Monitor for many different modulation formats * * Copyright (C) 1996 * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) * * Added eas parts - A. Maitland Bottoms 27 June 2000 * * Copyright (C) 2012-2014 * Elias Oenal (multimon-ng@eliasoenal.com) * * Copyright (C) 2024 * Jason Lingohr (jason@lucid.net.au) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ---------------------------------------------------------------------- */ #ifndef _MULTIMON_H #define _MULTIMON_H #include <stdint.h> #include <stdbool.h> #ifdef _MSC_VER #include "msvc_support.h" #endif /* ---------------------------------------------------------------------- */ extern const float costabf[0x400]; #define COS(x) costabf[(((x)>>6)&0x3ffu)] #define SIN(x) COS((x)+0xc000) /* ---------------------------------------------------------------------- */ enum { POCSAG_MODE_STANDARD = 0, POCSAG_MODE_NUMERIC = 1, POCSAG_MODE_ALPHA = 2, POCSAG_MODE_SKYPER = 3, POCSAG_MODE_AUTO = 4, }; enum EAS_L2_State { EAS_L2_IDLE = 0, EAS_L2_HEADER_SEARCH = 1, EAS_L2_READING_MESSAGE = 2, EAS_L2_READING_EOM = 3, }; enum EAS_L1_State { EAS_L1_IDLE = 0, EAS_L1_SYNC = 1, }; struct l2_state_clipfsk { unsigned char rxbuf[512]; unsigned char *rxptr; uint32_t rxstate; uint32_t rxbitstream; uint32_t rxbitbuf; }; struct l2_state_fmsfsk { unsigned char rxbuf[512]; unsigned char *rxptr; uint32_t rxstate; // used to track the SYNC pattern uint64_t rxbitstream; // holds RXed bits uint32_t rxbitcount; // counts RXed bits }; struct demod_state { const struct demod_param *dem_par; union { struct l2_state_fmsfsk fmsfsk; struct l2_state_clipfsk clipfsk; struct l2_state_uart { unsigned char rxbuf[8192]; unsigned char *rxptr; uint32_t rxstate; uint32_t rxbitstream; uint32_t rxbitbuf; } uart; struct l2_state_hdlc { unsigned char rxbuf[512]; unsigned char *rxptr; uint32_t rxstate; uint32_t rxbitstream; uint32_t rxbitbuf; } hdlc; struct l2_state_eas { char last_message[269]; char msg_buf[4][269]; char head_buf[4]; uint32_t headlen; uint32_t msglen; uint32_t msgno; uint32_t state; } eas; struct l2_state_pocsag { uint32_t rx_data; unsigned char state; // state machine unsigned char rx_bit; // bit counter, counts 32bits unsigned char rx_word; int32_t function; // POCSAG function int32_t address; // POCSAG address unsigned char buffer[512]; uint32_t numnibbles; uint32_t pocsag_total_error_count; uint32_t pocsag_corrected_error_count; uint32_t pocsag_corrected_1bit_error_count; uint32_t pocsag_corrected_2bit_error_count; uint32_t pocsag_uncorrected_error_count; uint32_t pocsag_total_bits_received; uint32_t pocsag_bits_processed_while_synced; uint32_t pocsag_bits_processed_while_not_synced; } pocsag; } l2; union { struct l1_state_poc5 { uint32_t dcd_shreg; uint32_t sphase; uint32_t subsamp; } poc5; struct l1_state_poc12 { uint32_t dcd_shreg; uint32_t sphase; uint32_t subsamp; } poc12; struct l1_state_poc24 { uint32_t dcd_shreg; uint32_t sphase; } poc24; struct l1_state_eas { unsigned int dcd_shreg; unsigned int sphase; unsigned char lasts; unsigned int subsamp; unsigned char byte_counter; int dcd_integrator; uint32_t state; } eas; struct l1_state_ufsk12 { unsigned int dcd_shreg; unsigned int sphase; unsigned int subsamp; } ufsk12; struct l1_state_clipfsk { unsigned int dcd_shreg; unsigned int sphase; uint32_t subsamp; } clipfsk; struct l1_state_fmsfsk { unsigned int dcd_shreg; unsigned int sphase; uint32_t subsamp; } fmsfsk; struct l1_state_afsk12 { uint32_t dcd_shreg; uint32_t sphase; uint32_t lasts; uint32_t subsamp; } afsk12; struct l1_state_afsk24 { unsigned int dcd_shreg; unsigned int sphase; unsigned int lasts; } afsk24; struct l1_state_hapn48 { unsigned int shreg; unsigned int sphase; float lvllo, lvlhi; } hapn48; struct l1_state_fsk96 { unsigned int dcd_shreg; unsigned int sphase; unsigned int descram; } fsk96; struct l1_state_dtmf { unsigned int ph[8]; float energy[4]; float tenergy[4][16]; int blkcount; int lastch; } dtmf; struct l1_state_selcall { unsigned int ph[16]; float energy[4]; float tenergy[4][32]; int blkcount; int lastch; int timeout; } selcall; struct l1_state_morse { uint64_t current_sequence; int_fast16_t threshold_ctr; int_fast32_t detection_threshold; int_fast32_t filtered; int_fast32_t samples_since_change; int_fast32_t signal_max; int_fast32_t glitches; int_fast32_t erroneous_chars; int_fast32_t decoded_chars; int_fast16_t time_unit_dit_dah_samples; int_fast16_t time_unit_gaps_samples; int_fast16_t lowpass_strength; int_fast16_t holdoff_samples; int_fast8_t current_state; // High = 1, Low = 0 } morse; struct l1_state_dumpcsv { uint32_t current_sequence; } dumpcsv; struct Flex * flex; struct Flex_Next * flex_next; struct l1_state_x10 { uint32_t current_sequence; uint32_t last_rise; short current_state; short current_stage; char b[4]; char bi; char bstring[42]; } x10; #ifndef NO_X11 struct l1_state_scope { int datalen; int dispnum; float data[512]; } scope; #endif } l1; }; typedef struct buffer { const short* sbuffer; const float* fbuffer; } buffer_t; struct demod_param { const char *name; bool float_samples; // if false samples are short instead unsigned int samplerate; unsigned int overlap; void (*init)(struct demod_state *s); void (*demod)(struct demod_state *s, buffer_t buffer, int length); void (*deinit)(struct demod_state *s); }; /* ---------------------------------------------------------------------- */ extern const struct demod_param demod_poc5; extern const struct demod_param demod_poc12; extern const struct demod_param demod_poc24; extern const struct demod_param demod_flex; extern const struct demod_param demod_flex_next; extern const struct demod_param demod_eas; extern const struct demod_param demod_ufsk1200; extern const struct demod_param demod_clipfsk; extern const struct demod_param demod_fmsfsk; extern const struct demod_param demod_afsk1200; extern const struct demod_param demod_afsk2400; extern const struct demod_param demod_afsk2400_2; extern const struct demod_param demod_afsk2400_3; extern const struct demod_param demod_hapn4800; extern const struct demod_param demod_fsk9600; extern const struct demod_param demod_dtmf; extern const struct demod_param demod_zvei1; extern const struct demod_param demod_zvei2; extern const struct demod_param demod_zvei3; extern const struct demod_param demod_dzvei; extern const struct demod_param demod_pzvei; extern const struct demod_param demod_eea; extern const struct demod_param demod_eia; extern const struct demod_param demod_ccir; extern const struct demod_param demod_morse; extern const struct demod_param demod_x10; extern const struct demod_param demod_dumpcsv; #ifndef NO_X11 extern const struct demod_param demod_scope; #endif #ifndef NO_X11 #define SCOPE_DEMOD , &demod_scope #else #define SCOPE_DEMOD #endif #define ALL_DEMOD &demod_poc5, &demod_poc12, &demod_poc24, &demod_flex, &demod_flex_next, &demod_eas, &demod_ufsk1200, &demod_clipfsk, &demod_fmsfsk, \ &demod_afsk1200, &demod_afsk2400, &demod_afsk2400_2, &demod_afsk2400_3, &demod_hapn4800, \ &demod_fsk9600, &demod_dtmf, &demod_zvei1, &demod_zvei2, &demod_zvei3, &demod_dzvei, \ &demod_pzvei, &demod_eea, &demod_eia, &demod_ccir, &demod_morse, &demod_dumpcsv, &demod_x10 SCOPE_DEMOD /* ---------------------------------------------------------------------- */ void _verbprintf(int verb_level, const char *fmt, ...); #if !defined(MAX_VERBOSE_LEVEL) # define MAX_VERBOSE_LEVEL 0 #endif #define verbprintf(level, ...) \ do { if (level <= MAX_VERBOSE_LEVEL) _verbprintf(level, __VA_ARGS__); } while (0) void hdlc_init(struct demod_state *s); void hdlc_rxbit(struct demod_state *s, int bit); void uart_init(struct demod_state *s); void uart_rxbit(struct demod_state *s, int bit); void clip_init(struct demod_state *s); void clip_rxbit(struct demod_state *s, int bit); void fms_init(struct demod_state *s); void fms_rxbit(struct demod_state *s, int bit); void pocsag_init(struct demod_state *s); void pocsag_rxbit(struct demod_state *s, int32_t bit); void pocsag_deinit(struct demod_state *s); void selcall_init(struct demod_state *s); void selcall_demod(struct demod_state *s, const float *buffer, int length, const unsigned int *selcall_freq, const char *const name); void selcall_deinit(struct demod_state *s); void xdisp_terminate(int cnum); int xdisp_start(void); int xdisp_update(int cnum, float *f); void print_json(int argc, char **argv); /* ---------------------------------------------------------------------- */ #endif /* _MULTIMON_H */
最新发布
11-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值