|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include "AsaTypes.hpp" |
| 4 | +#include "SolverTypes.h" |
| 5 | + |
| 6 | +#include <algorithm> |
| 7 | +#include <cstdint> |
| 8 | + |
| 9 | +namespace Solvers::Stylus { |
| 10 | + |
| 11 | +class AftCoorProcess { |
| 12 | +public: |
| 13 | + bool m_enabled = true; |
| 14 | + |
| 15 | + // ── Lock thresholds (flash params equivalent) ── |
| 16 | + // In-band thresholds (coordinate within sensor interior) |
| 17 | + uint8_t m_lockFlashInBandX = 10; // flash[0xA5A] |
| 18 | + uint8_t m_lockFlashInBandY = 10; // flash[0xA5B] |
| 19 | + |
| 20 | + // Edge thresholds (coordinate near sensor boundary) |
| 21 | + uint8_t m_lockFlashEdgeX = 20; // flash[0xA58] |
| 22 | + uint8_t m_lockFlashEdgeY = 20; // flash[0xA59] |
| 23 | + |
| 24 | + // Sensor dimensions (from asaPrmt) |
| 25 | + int m_sensorTxCount = 60; // bTxCount |
| 26 | + int m_sensorRxCount = 40; // bRxCount |
| 27 | + int m_sensorDim1 = 60; // wField00 |
| 28 | + int m_sensorDim2 = 40; // wField02 |
| 29 | + |
| 30 | + // Bypass gate: skip lock when this ASA-style flag is active |
| 31 | + bool m_bypassLock = false; |
| 32 | + |
| 33 | + inline void Reset() { |
| 34 | + m_startX = 0; |
| 35 | + m_startY = 0; |
| 36 | + m_lockOffsetX = 0; |
| 37 | + m_lockOffsetY = 0; |
| 38 | + m_flagLockX = false; |
| 39 | + m_flagLockY = false; |
| 40 | + m_prevPressure = 0; |
| 41 | + } |
| 42 | + |
| 43 | + inline void Process(HeatmapFrame& frame) { |
| 44 | + auto& runtime = frame.stylus.runtime; |
| 45 | + auto& coor = runtime.post.finalCoor; |
| 46 | + const uint16_t curPressure = runtime.pressure.outputPressure; |
| 47 | + |
| 48 | + if (!m_enabled || m_bypassLock) { |
| 49 | + // Pass-through: just clamp to sensor bounds |
| 50 | + if (coor.valid) { |
| 51 | + ClampToSensor(coor); |
| 52 | + } |
| 53 | + m_prevPressure = curPressure; |
| 54 | + return; |
| 55 | + } |
| 56 | + |
| 57 | + if (!coor.valid) { |
| 58 | + Reset(); |
| 59 | + m_prevPressure = curPressure; |
| 60 | + return; |
| 61 | + } |
| 62 | + |
| 63 | + // ── Select thresholds based on coordinate position ── |
| 64 | + // TSACore: if coor < 0x401 or coor >= (count-1)*0x400 → edge threshold |
| 65 | + const int32_t minBound = 0x401; |
| 66 | + const int32_t maxBoundX = (m_sensorTxCount - 1) * Asa::kCoorUnit; |
| 67 | + const int32_t maxBoundY = (m_sensorRxCount - 1) * Asa::kCoorUnit; |
| 68 | + |
| 69 | + uint32_t thresholdX; |
| 70 | + uint32_t thresholdY; |
| 71 | + |
| 72 | + if (coor.dim1 < minBound || coor.dim2 < minBound || |
| 73 | + coor.dim1 >= maxBoundX || coor.dim2 >= maxBoundY) { |
| 74 | + // Near boundary → use edge thresholds (more tolerant) |
| 75 | + thresholdX = (static_cast<uint32_t>(m_lockFlashEdgeX) * |
| 76 | + static_cast<uint32_t>(m_sensorTxCount) * Asa::kCoorUnit) / |
| 77 | + static_cast<uint32_t>(std::max(1, m_sensorDim1)); |
| 78 | + thresholdY = (static_cast<uint32_t>(m_lockFlashEdgeY) * |
| 79 | + static_cast<uint32_t>(m_sensorRxCount) * Asa::kCoorUnit) / |
| 80 | + static_cast<uint32_t>(std::max(1, m_sensorDim2)); |
| 81 | + } else { |
| 82 | + // Interior → use in-band thresholds |
| 83 | + thresholdX = (static_cast<uint32_t>(m_lockFlashInBandX) * |
| 84 | + static_cast<uint32_t>(m_sensorTxCount) * Asa::kCoorUnit) / |
| 85 | + static_cast<uint32_t>(std::max(1, m_sensorDim1)); |
| 86 | + thresholdY = (static_cast<uint32_t>(m_lockFlashInBandY) * |
| 87 | + static_cast<uint32_t>(m_sensorRxCount) * Asa::kCoorUnit) / |
| 88 | + static_cast<uint32_t>(std::max(1, m_sensorDim2)); |
| 89 | + } |
| 90 | + |
| 91 | + // ── Pen-down transition: lock to start position ── |
| 92 | + if (curPressure != 0 && m_prevPressure == 0) { |
| 93 | + m_startX = coor.dim1; |
| 94 | + m_startY = coor.dim2; |
| 95 | + m_flagLockX = true; |
| 96 | + m_flagLockY = true; |
| 97 | + m_lockOffsetX = 0; |
| 98 | + m_lockOffsetY = 0; |
| 99 | + } |
| 100 | + |
| 101 | + // ── X-axis lock ── |
| 102 | + if (m_flagLockX) { |
| 103 | + const int32_t diff = coor.dim1 - m_startX; |
| 104 | + const uint32_t absDiff = static_cast<uint32_t>(std::abs(diff)); |
| 105 | + if (absDiff > thresholdX) { |
| 106 | + m_flagLockX = false; // movement exceeded threshold → release lock |
| 107 | + } |
| 108 | + if (m_flagLockX) { |
| 109 | + m_lockOffsetX = diff; // track offset while locked |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + // ── Y-axis lock ── |
| 114 | + if (m_flagLockY) { |
| 115 | + const int32_t diff = coor.dim2 - m_startY; |
| 116 | + const uint32_t absDiff = static_cast<uint32_t>(std::abs(diff)); |
| 117 | + if (absDiff > thresholdY) { |
| 118 | + m_flagLockY = false; |
| 119 | + } |
| 120 | + if (m_flagLockY) { |
| 121 | + m_lockOffsetY = diff; |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + // ── Apply offset and clamp ── |
| 126 | + int32_t finalX = coor.dim1 - m_lockOffsetX; |
| 127 | + int32_t finalY = coor.dim2 - m_lockOffsetY; |
| 128 | + |
| 129 | + finalX = std::clamp(finalX, 0, m_sensorTxCount * Asa::kCoorUnit); |
| 130 | + finalY = std::clamp(finalY, 0, m_sensorRxCount * Asa::kCoorUnit); |
| 131 | + |
| 132 | + coor.dim1 = finalX; |
| 133 | + coor.dim2 = finalY; |
| 134 | + |
| 135 | +#if EGOTOUCH_DIAG |
| 136 | + runtime.post.lockActiveX = m_flagLockX; |
| 137 | + runtime.post.lockActiveY = m_flagLockY; |
| 138 | + runtime.post.lockOffsetX = m_lockOffsetX; |
| 139 | + runtime.post.lockOffsetY = m_lockOffsetY; |
| 140 | + runtime.post.lockThresholdX = static_cast<int32_t>(thresholdX); |
| 141 | + runtime.post.lockThresholdY = static_cast<int32_t>(thresholdY); |
| 142 | +#endif |
| 143 | + |
| 144 | + m_prevPressure = curPressure; |
| 145 | + } |
| 146 | + |
| 147 | +private: |
| 148 | + int32_t m_startX = 0; |
| 149 | + int32_t m_startY = 0; |
| 150 | + int32_t m_lockOffsetX = 0; |
| 151 | + int32_t m_lockOffsetY = 0; |
| 152 | + bool m_flagLockX = false; |
| 153 | + bool m_flagLockY = false; |
| 154 | + uint16_t m_prevPressure = 0; |
| 155 | + |
| 156 | + inline void ClampToSensor(Asa::AsaCoorResult& coor) const { |
| 157 | + coor.dim1 = std::clamp(coor.dim1, 0, m_sensorTxCount * Asa::kCoorUnit); |
| 158 | + coor.dim2 = std::clamp(coor.dim2, 0, m_sensorRxCount * Asa::kCoorUnit); |
| 159 | + } |
| 160 | +}; |
| 161 | + |
| 162 | +} // namespace Solvers::Stylus |
0 commit comments