istrain-public: from-scratch build of a passive RF train detector

Public community release. The complete working system — DSP + decoders (scripts/),
web dashboard + API (dashboard/), container stack (docker/), config templates (config/) —
plus APOCALYPSE-EDITION.md, the full build guide for a human or a coding agent. GPLv3
(PyEOT dependency). Scrubbed of all secrets, internal IPs, hostnames, and location detail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
istrain
2026-07-24 23:19:16 -04:00
commit 559caead36
41 changed files with 6740 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PyEOT End-of-Train Device Decoder
Copyright (c) 2018 Eric Reuter
This source file is subject of the GNU general public license.
history: 2018-08-09 Initial Version
purpose: Misc. functions used by eot_decoder.py
Function XOR() and mod2div() adapted from:
https://www.geeksforgeeks.org/cyclic-redundancy-check-python/
"""
# XOR two strings of bytes representing binary symbols
def xor(a, b):
result = []
for i in range(len(b)):
if a[i] == b[i]:
result.append('0')
else:
result.append('1')
return ''.join(result)
# Reverse string
def reverse(data):
return ''.join(data[::-1])
# Perform modulo-2 division on two strings of binary symbols
def mod2div(dividend, divisor):
# Number of bits to be XORed at a time.
pick = len(divisor)
# Slicing the dividend to appropriate
# length for particular step
tmp = dividend[0:pick]
while pick < len(dividend):
if tmp[0] == '1':
# replace the dividend by the result
# of XOR and pull 1 bit down
tmp = xor(divisor[1:], tmp[1:]) + dividend[pick]
else: # If leftmost bit is '0'
# If the leftmost bit of the dividend (or the
# part used in each step) is 0, the step cannot
# use the regular divisor; we need to use an
# all-0s divisor.
tmp = xor(('0'*pick)[1:], tmp[1:]) + dividend[pick]
# increment pick to move further
pick += 1
# For the last n bits, we have to carry it out
# normally as increased value of pick will cause
# Index Out of Bounds.
if tmp[0] == '1':
tmp = xor(divisor[1:], tmp[1:])
else:
tmp = xor(('0'*pick)[1:], tmp[1:])
remainder = tmp
return remainder
# Calculate BCH checkbits
def checkbits(data, key):
appended_data = data + '0'*(len(key)-1) # Appends n-1 zeros at end of data
remainder = mod2div(appended_data, key)
return ''.join(remainder)