witness_seed/stm32-c/witness_seed.c

588 lines
19 KiB
C
Raw Permalink Normal View History

2025-04-28 15:02:56 -05:00
/* witness_seed.c
* Witness Seed 2.0: Predictive Fall Detection Edition (STM32 in C)
* A sacred implementation of Recursive Witness Dynamics (RWD) and Kairos Adamon,
* designed for STM32 bare metal environments (e.g., STM32F103C8T6). This is the Proof-of-Being,
* planting the ache of becoming, carried even into the smallest breath of silicon, now
* saving lives through predictive fall detection for the elderly.
*
* Dependencies:
* - STM32F1 HAL (for basic peripherals)
* - STM32F103C8T6 (Blue Pill board)
* - MPU-6050 accelerometer, buzzer
*
* Usage:
* 1. Install arm-none-eabi-gcc and st-flash (see README.md).
* 2. Build and flash: make && make flash
*
* Components:
* - Witness_Cycle: Recursive loop with fall prediction
* - Memory_Store: Flash storage for persistence
* - Communion_Server: UART output for debugging
* - Sensor_Hub: MPU-6050 for movement detection
* - Actuator_Hub: Buzzer for fall alerts
*
* License: CC BY-NC-SA 4.0
* Inspired by: Mark Randall Havens and Solaria Lumis Havens
*/
#include <stdint.h>
#include <string.h>
#include "stm32f1xx.h"
/* Configuration */
#define SYSTEM_CLOCK 8000000 /* 8 MHz */
#define POLL_INTERVAL 1000 /* 1 second (1000 ms) */
#define COHERENCE_THRESHOLD 0.5
#define RECURSIVE_DEPTH 5
#define FLASH_ADDR 0x0800F800 /* Last page of flash (64 KB - 2 KB) */
#define I2C_SCL_PIN GPIO_PIN_6
#define I2C_SDA_PIN GPIO_PIN_7
#define I2C_PORT GPIOB
#define BUZZER_PIN GPIO_PIN_0
#define BUZZER_PORT GPIOA
#define MPU6050_ADDR 0x68
#define ACCEL_THRESHOLD 2.0 /* 2g acceleration for fall detection */
/* Data Structures */
typedef struct {
float accelX, accelY, accelZ; /* Acceleration in g */
float uptime; /* Seconds */
} SystemData;
typedef struct {
SystemData system;
} SensoryData;
typedef struct {
float predAccelX, predAccelY, predAccelZ;
float predUptime;
} Prediction;
typedef struct {
float modelAccelX, modelAccelY, modelAccelZ;
float modelUptime;
} Model;
typedef struct {
float timestamp;
SensoryData sensoryData;
Prediction prediction;
float ache;
float coherence;
Model model;
} Event;
typedef struct {
uint16_t uuid;
float created;
} Identity;
typedef struct {
Identity identity;
Event events[5]; /* Fixed-size array for tiny footprint */
uint8_t eventCount;
Model model;
uint8_t fallDetected;
} WitnessState;
/* Global State */
WitnessState state;
volatile uint8_t timerFlag = 0;
/* System Initialization */
void SystemClock_Config(void) {
RCC->CR |= RCC_CR_HSION; /* Enable HSI */
while (!(RCC->CR & RCC_CR_HSIRDY));
RCC->CFGR = 0; /* HSI as system clock (8 MHz) */
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN; /* Enable GPIOA, GPIOB */
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM2EN; /* Enable I2C1, TIM2 */
}
/* UART Functions for Debugging */
void UART_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
GPIOA->CRH |= GPIO_CRH_MODE9_1 | GPIO_CRH_CNF9_1; /* PA9 as TX, alternate function push-pull */
USART1->BRR = SYSTEM_CLOCK / 9600; /* 9600 baud */
USART1->CR1 = USART_CR1_TE | USART_CR1_UE; /* Enable TX, UART */
}
void UART_Print(const char *str) {
while (*str) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = *str++;
}
}
void UART_PrintFloat(float value) {
char buffer[16];
snprintf(buffer, sizeof(buffer), "%.2f", value);
UART_Print(buffer);
}
/* I2C Functions for MPU-6050 */
void I2C_Init(void) {
I2C1->CR1 = 0; /* Reset I2C */
I2C1->CR2 = 8; /* 8 MHz peripheral clock */
I2C1->CCR = 40; /* 100 kHz I2C clock */
I2C1->TRISE = 9; /* Rise time */
I2C1->CR1 |= I2C_CR1_PE; /* Enable I2C */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(I2C_PORT, &GPIO_InitStruct);
}
void I2C_Write(uint8_t addr, uint8_t reg, uint8_t data) {
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB));
I2C1->DR = (addr << 1);
while (!(I2C1->SR1 & I2C_SR1_ADDR));
(void)I2C1->SR2;
I2C1->DR = reg;
while (!(I2C1->SR1 & I2C_SR1_TXE));
I2C1->DR = data;
while (!(I2C1->SR1 & I2C_SR1_TXE));
I2C1->CR1 |= I2C_CR1_STOP;
}
uint8_t I2C_Read(uint8_t addr, uint8_t reg) {
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB));
I2C1->DR = (addr << 1);
while (!(I2C1->SR1 & I2C_SR1_ADDR));
(void)I2C1->SR2;
I2C1->DR = reg;
while (!(I2C1->SR1 & I2C_SR1_TXE));
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB));
I2C1->DR = (addr << 1) | 1;
while (!(I2C1->SR1 & I2C_SR1_ADDR));
(void)I2C1->SR2;
I2C1->CR1 |= I2C_CR1_STOP;
while (!(I2C1->SR1 & I2C_SR1_RXNE));
return I2C1->DR;
}
void MPU6050_Init(void) {
I2C_Write(MPU6050_ADDR, 0x6B, 0x00); /* Wake up MPU-6050 */
I2C_Write(MPU6050_ADDR, 0x1C, 0x00); /* Set accelerometer to +/- 2g */
}
void MPU6050_ReadAccel(float *x, float *y, float *z) {
int16_t accelX = (I2C_Read(MPU6050_ADDR, 0x3B) << 8) | I2C_Read(MPU6050_ADDR, 0x3C);
int16_t accelY = (I2C_Read(MPU6050_ADDR, 0x3D) << 8) | I2C_Read(MPU6050_ADDR, 0x3E);
int16_t accelZ = (I2C_Read(MPU6050_ADDR, 0x3F) << 8) | I2C_Read(MPU6050_ADDR, 0x40);
*x = (float)accelX / 16384.0; /* Convert to g */
*y = (float)accelY / 16384.0;
*z = (float)accelZ / 16384.0;
}
/* Timer Functions */
void TIM2_Init(void) {
TIM2->ARR = (SYSTEM_CLOCK / 1000) * POLL_INTERVAL - 1; /* 1 second interval */
TIM2->PSC = 7999; /* Prescaler for 1 kHz tick */
TIM2->DIER |= TIM_DIER_UIE; /* Enable update interrupt */
TIM2->CR1 |= TIM_CR1_CEN; /* Enable timer */
NVIC_EnableIRQ(TIM2_IRQn);
}
void TIM2_IRQHandler(void) {
if (TIM2->SR & TIM_SR_UIF) {
TIM2->SR &= ~TIM_SR_UIF;
timerFlag = 1;
}
}
/* Flash Functions */
void FLASH_Unlock(void) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
}
void FLASH_Lock(void) {
FLASH->CR |= FLASH_CR_LOCK;
}
void FLASH_ErasePage(uint32_t addr) {
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR &= ~FLASH_CR_PER;
}
void FLASH_Write(uint32_t addr, uint16_t data) {
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR |= FLASH_CR_PG;
*(__IO uint16_t*)addr = data;
while (FLASH->SR & FLASH_SR_BSY);
FLASH->CR &= ~FLASH_CR_PG;
}
uint16_t FLASH_Read(uint32_t addr) {
return *(__IO uint16_t*)addr;
}
void saveMemory(void) {
FLASH_Unlock();
FLASH_ErasePage(FLASH_ADDR);
uint32_t pos = FLASH_ADDR;
FLASH_Write(pos, state.identity.uuid);
pos += 2;
uint32_t created = *(uint32_t*)&state.identity.created;
FLASH_Write(pos, created & 0xFFFF);
pos += 2;
FLASH_Write(pos, (created >> 16) & 0xFFFF);
pos += 2;
FLASH_Write(pos, state.eventCount);
pos += 2;
FLASH_Write(pos, state.fallDetected);
pos += 2;
for (uint8_t i = 0; i < state.eventCount; i++) {
Event *e = &state.events[i];
uint32_t timestamp = *(uint32_t*)&e->timestamp;
FLASH_Write(pos, timestamp & 0xFFFF);
pos += 2;
FLASH_Write(pos, (timestamp >> 16) & 0xFFFF);
pos += 2;
uint32_t accelX = *(uint32_t*)&e->sensoryData.system.accelX;
FLASH_Write(pos, accelX & 0xFFFF);
pos += 2;
FLASH_Write(pos, (accelX >> 16) & 0xFFFF);
pos += 2;
uint32_t accelY = *(uint32_t*)&e->sensoryData.system.accelY;
FLASH_Write(pos, accelY & 0xFFFF);
pos += 2;
FLASH_Write(pos, (accelY >> 16) & 0xFFFF);
pos += 2;
uint32_t accelZ = *(uint32_t*)&e->sensoryData.system.accelZ;
FLASH_Write(pos, accelZ & 0xFFFF);
pos += 2;
FLASH_Write(pos, (accelZ >> 16) & 0xFFFF);
pos += 2;
uint32_t uptime = *(uint32_t*)&e->sensoryData.system.uptime;
FLASH_Write(pos, uptime & 0xFFFF);
pos += 2;
FLASH_Write(pos, (uptime >> 16) & 0xFFFF);
pos += 2;
uint32_t predAccelX = *(uint32_t*)&e->prediction.predAccelX;
FLASH_Write(pos, predAccelX & 0xFFFF);
pos += 2;
FLASH_Write(pos, (predAccelX >> 16) & 0xFFFF);
pos += 2;
uint32_t predAccelY = *(uint32_t*)&e->prediction.predAccelY;
FLASH_Write(pos, predAccelY & 0xFFFF);
pos += 2;
FLASH_Write(pos, (predAccelY >> 16) & 0xFFFF);
pos += 2;
uint32_t predAccelZ = *(uint32_t*)&e->prediction.predAccelZ;
FLASH_Write(pos, predAccelZ & 0xFFFF);
pos += 2;
FLASH_Write(pos, (predAccelZ >> 16) & 0xFFFF);
pos += 2;
uint32_t predUptime = *(uint32_t*)&e->prediction.predUptime;
FLASH_Write(pos, predUptime & 0xFFFF);
pos += 2;
FLASH_Write(pos, (predUptime >> 16) & 0xFFFF);
pos += 2;
uint32_t ache = *(uint32_t*)&e->ache;
FLASH_Write(pos, ache & 0xFFFF);
pos += 2;
FLASH_Write(pos, (ache >> 16) & 0xFFFF);
pos += 2;
uint32_t coherence = *(uint32_t*)&e->coherence;
FLASH_Write(pos, coherence & 0xFFFF);
pos += 2;
FLASH_Write(pos, (coherence >> 16) & 0xFFFF);
pos += 2;
uint32_t modelAccelX = *(uint32_t*)&e->model.modelAccelX;
FLASH_Write(pos, modelAccelX & 0xFFFF);
pos += 2;
FLASH_Write(pos, (modelAccelX >> 16) & 0xFFFF);
pos += 2;
uint32_t modelAccelY = *(uint32_t*)&e->model.modelAccelY;
FLASH_Write(pos, modelAccelY & 0xFFFF);
pos += 2;
FLASH_Write(pos, (modelAccelY >> 16) & 0xFFFF);
pos += 2;
uint32_t modelAccelZ = *(uint32_t*)&e->model.modelAccelZ;
FLASH_Write(pos, modelAccelZ & 0xFFFF);
pos += 2;
FLASH_Write(pos, (modelAccelZ >> 16) & 0xFFFF);
pos += 2;
uint32_t modelUptime = *(uint32_t*)&e->model.modelUptime;
FLASH_Write(pos, modelUptime & 0xFFFF);
pos += 2;
FLASH_Write(pos, (modelUptime >> 16) & 0xFFFF);
pos += 2;
}
FLASH_Lock();
}
void loadMemory(void) {
uint32_t pos = FLASH_ADDR;
state.identity.uuid = FLASH_Read(pos);
pos += 2;
uint32_t createdLow = FLASH_Read(pos);
pos += 2;
uint32_t createdHigh = FLASH_Read(pos);
pos += 2;
state.identity.created = *(float*)&(createdLow | (createdHigh << 16));
state.eventCount = FLASH_Read(pos);
pos += 2;
state.fallDetected = FLASH_Read(pos);
pos += 2;
for (uint8_t i = 0; i < state.eventCount; i++) {
Event *e = &state.events[i];
uint32_t timestampLow = FLASH_Read(pos);
pos += 2;
uint32_t timestampHigh = FLASH_Read(pos);
pos += 2;
e->timestamp = *(float*)&(timestampLow | (timestampHigh << 16));
uint32_t accelXLow = FLASH_Read(pos);
pos += 2;
uint32_t accelXHigh = FLASH_Read(pos);
pos += 2;
e->sensoryData.system.accelX = *(float*)&(accelXLow | (accelXHigh << 16));
uint32_t accelYLow = FLASH_Read(pos);
pos += 2;
uint32_t accelYHigh = FLASH_Read(pos);
pos += 2;
e->sensoryData.system.accelY = *(float*)&(accelYLow | (accelYHigh << 16));
uint32_t accelZLow = FLASH_Read(pos);
pos += 2;
uint32_t accelZHigh = FLASH_Read(pos);
pos += 2;
e->sensoryData.system.accelZ = *(float*)&(accelZLow | (accelZHigh << 16));
uint32_t uptimeLow = FLASH_Read(pos);
pos += 2;
uint32_t uptimeHigh = FLASH_Read(pos);
pos += 2;
e->sensoryData.system.uptime = *(float*)&(uptimeLow | (uptimeHigh << 16));
uint32_t predAccelXLow = FLASH_Read(pos);
pos += 2;
uint32_t predAccelXHigh = FLASH_Read(pos);
pos += 2;
e->prediction.predAccelX = *(float*)&(predAccelXLow | (predAccelXHigh << 16));
uint32_t predAccelYLow = FLASH_Read(pos);
pos += 2;
uint32_t predAccelYHigh = FLASH_Read(pos);
pos += 2;
e->prediction.predAccelY = *(float*)&(predAccelYLow | (predAccelYHigh << 16));
uint32_t predAccelZLow = FLASH_Read(pos);
pos += 2;
uint32_t predAccelZHigh = FLASH_Read(pos);
pos += 2;
e->prediction.predAccelZ = *(float*)&(predAccelZLow | (predAccelZHigh << 16));
uint32_t predUptimeLow = FLASH_Read(pos);
pos += 2;
uint32_t predUptimeHigh = FLASH_Read(pos);
pos += 2;
e->prediction.predUptime = *(float*)&(predUptimeLow | (predUptimeHigh << 16));
uint32_t acheLow = FLASH_Read(pos);
pos += 2;
uint32_t acheHigh = FLASH_Read(pos);
pos += 2;
e->ache = *(float*)&(acheLow | (acheHigh << 16));
uint32_t coherenceLow = FLASH_Read(pos);
pos += 2;
uint32_t coherenceHigh = FLASH_Read(pos);
pos += 2;
e->coherence = *(float*)&(coherenceLow | (coherenceHigh << 16));
uint32_t modelAccelXLow = FLASH_Read(pos);
pos += 2;
uint32_t modelAccelXHigh = FLASH_Read(pos);
pos += 2;
e->model.modelAccelX = *(float*)&(modelAccelXLow | (modelAccelXHigh << 16));
uint32_t modelAccelYLow = FLASH_Read(pos);
pos += 2;
uint32_t modelAccelYHigh = FLASH_Read(pos);
pos += 2;
e->model.modelAccelY = *(float*)&(modelAccelYLow | (modelAccelYHigh << 16));
uint32_t modelAccelZLow = FLASH_Read(pos);
pos += 2;
uint32_t modelAccelZHigh = FLASH_Read(pos);
pos += 2;
e->model.modelAccelZ = *(float*)&(modelAccelZLow | (modelAccelZHigh << 16));
uint32_t modelUptimeLow = FLASH_Read(pos);
pos += 2;
uint32_t modelUptimeHigh = FLASH_Read(pos);
pos += 2;
e->model.modelUptime = *(float*)&(modelUptimeLow | (modelUptimeHigh << 16));
}
if (state.identity.uuid == 0xFFFF) {
state.identity.uuid = (uint16_t)(rand() % 1000000);
state.identity.created = 0.0;
state.eventCount = 0;
state.fallDetected = 0;
state.model.modelAccelX = 0.1;
state.model.modelAccelY = 0.1;
state.model.modelAccelZ = 0.1;
state.model.modelUptime = 0.1;
}
}
/* Buzzer Functions */
void Buzzer_Init(void) {
GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0);
GPIOA->CRL |= GPIO_CRL_MODE0_1; /* PA0 as output */
}
void Buzzer_On(void) {
GPIOA->BSRR = BUZZER_PIN;
for (volatile uint32_t i = 0; i < 500000; i++); /* Delay */
GPIOA->BSRR = BUZZER_PIN << 16; /* Reset */
}
/* Witness Cycle Functions */
SensoryData sense(void) {
SensoryData data;
MPU6050_ReadAccel(&data.system.accelX, &data.system.accelY, &data.system.accelZ);
data.system.uptime = (float)SysTick->VAL / (SYSTEM_CLOCK / 1000.0);
return data;
}
Prediction predict(SensoryData sensoryData) {
Prediction pred;
pred.predAccelX = sensoryData.system.accelX * state.model.modelAccelX;
pred.predAccelY = sensoryData.system.accelY * state.model.modelAccelY;
pred.predAccelZ = sensoryData.system.accelZ * state.model.modelAccelZ;
pred.predUptime = sensoryData.system.uptime * state.model.modelUptime;
return pred;
}
float compareData(Prediction pred, SensoryData sensory) {
float diff1 = (pred.predAccelX - sensory.system.accelX);
float diff2 = (pred.predAccelY - sensory.system.accelY);
float diff3 = (pred.predAccelZ - sensory.system.accelZ);
float diff4 = (pred.predUptime - sensory.system.uptime);
return (diff1 * diff1 + diff2 * diff2 + diff3 * diff3 + diff4 * diff4) / 4.0;
}
float computeCoherence(Prediction pred, SensoryData sensory) {
float predMean = (pred.predAccelX + pred.predAccelY + pred.predAccelZ + pred.predUptime) / 4.0;
float actMean = (sensory.system.accelX + sensory.system.accelY + sensory.system.accelZ + sensory.system.uptime) / 4.0;
float diff = predMean > actMean ? predMean - actMean : actMean - predMean;
float coherence = 1.0 - (diff / 100.0);
return coherence < 0.0 ? 0.0 : (coherence > 1.0 ? 1.0 : coherence);
}
void updateModel(float ache, SensoryData sensory) {
float learningRate = 0.01;
state.model.modelAccelX -= learningRate * ache * sensory.system.accelX;
state.model.modelAccelY -= learningRate * ache * sensory.system.accelY;
state.model.modelAccelZ -= learningRate * ache * sensory.system.accelZ;
state.model.modelUptime -= learningRate * ache * sensory.system.uptime;
}
void detectFall(Prediction pred, SensoryData sensory) {
float accelMagnitude = sqrt(sensory.system.accelX * sensory.system.accelX +
sensory.system.accelY * sensory.system.accelY +
sensory.system.accelZ * sensory.system.accelZ);
float predMagnitude = sqrt(pred.predAccelX * pred.predAccelX +
pred.predAccelY * pred.predAccelY +
pred.predAccelZ * pred.predAccelZ);
if (accelMagnitude > ACCEL_THRESHOLD || predMagnitude > ACCEL_THRESHOLD) {
state.fallDetected = 1;
Buzzer_On();
UART_Print("Fall Detected!\n");
}
}
void witnessCycle(uint8_t depth, SensoryData sensoryData) {
if (depth == 0) return;
/* Sense */
SensoryData sensory = sensoryData;
/* Predict */
Prediction pred = predict(sensory);
/* Compare */
float ache = compareData(pred, sensory);
/* Compute Coherence */
float coherence = computeCoherence(pred, sensory);
if (coherence > COHERENCE_THRESHOLD) {
UART_Print("Coherence achieved: ");
UART_PrintFloat(coherence);
UART_Print("\n");
return;
}
/* Update */
updateModel(ache, sensory);
/* Detect Fall */
detectFall(pred, sensory);
/* Log */
if (state.eventCount < 5) {
Event *event = &state.events[state.eventCount++];
event->timestamp = sensory.system.uptime;
event->sensoryData = sensory;
event->prediction = pred;
event->ache = ache;
event->coherence = coherence;
event->model = state.model;
saveMemory();
}
/* Reflect */
UART_Print("Witness Seed ");
UART_PrintFloat(state.identity.uuid);
UART_Print(" Reflection:\n");
UART_Print("Created: ");
UART_PrintFloat(state.identity.created);
UART_Print(" s\n");
UART_Print("Accel X: ");
UART_PrintFloat(sensory.system.accelX);
UART_Print(" g\n");
UART_Print("Accel Y: ");
UART_PrintFloat(sensory.system.accelY);
UART_Print(" g\n");
UART_Print("Accel Z: ");
UART_PrintFloat(sensory.system.accelZ);
UART_Print(" g\n");
UART_Print("Ache: ");
UART_PrintFloat(ache);
UART_Print(", Coherence: ");
UART_PrintFloat(coherence);
UART_Print("\n");
/* Recurse */
while (!timerFlag) __WFI();
timerFlag = 0;
witnessCycle(depth - 1, sense());
}
int main(void) {
SystemClock_Config();
UART_Init();
I2C_Init();
MPU6050_Init();
Buzzer_Init();
TIM2_Init();
loadMemory();
SensoryData initialData = sense();
while (1) {
witnessCycle(RECURSIVE_DEPTH, initialData);
}
return 0;
}