Files
250928_esp32_spi_sdcard_ads…/transmit.h
byun f24b80238f 00003 전송웹추가
웹페이지 하나 더 추가 하고 싶은데 (포트생성) 이 신규 페이지는 can data를 송신 하는 목적의 페이지로 can 신호id, messagy type, message data(hex) 를 설정할 수 있게 하고 여러 신호들을 조합으로 송신할 수 있게, 그리고 특정 시간마다 송신할 수 있게 기능을 추가 할 수 있어? 해당페이지는 차후 수정이 용이하게 파일도 추가했으면 좋겠어
2025-10-05 07:10:14 +00:00

446 lines
16 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef TRANSMIT_H
#define TRANSMIT_H
const char transmit_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CAN Transmitter</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 { font-size: 2.5em; margin-bottom: 10px; }
.header p { opacity: 0.9; font-size: 1.1em; }
.nav {
background: #2c3e50;
padding: 15px 30px;
display: flex;
gap: 20px;
}
.nav a {
color: white;
text-decoration: none;
padding: 10px 20px;
border-radius: 5px;
transition: all 0.3s;
}
.nav a:hover { background: #34495e; }
.nav a.active { background: #3498db; }
.content { padding: 30px; }
.message-form {
background: #f8f9fa;
padding: 25px;
border-radius: 10px;
margin-bottom: 20px;
}
.form-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 15px;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-group label {
font-weight: 600;
margin-bottom: 5px;
color: #333;
}
.form-group input, .form-group select {
padding: 10px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 1em;
font-family: 'Courier New', monospace;
}
.form-group input:focus, .form-group select:focus {
outline: none;
border-color: #f093fb;
}
.data-bytes {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 10px;
}
.data-bytes input {
text-align: center;
text-transform: uppercase;
}
.btn {
padding: 12px 25px;
border: none;
border-radius: 5px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
}
.btn-success {
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
}
.btn-danger {
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
color: white;
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.3); }
.message-list {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
}
.message-item {
background: white;
padding: 15px;
margin-bottom: 10px;
border-radius: 8px;
display: grid;
grid-template-columns: 100px 80px 1fr 150px 120px;
gap: 15px;
align-items: center;
border-left: 4px solid #f093fb;
}
.message-item.active {
border-left-color: #38ef7d;
background: #f0fff4;
}
.message-id { font-weight: 700; color: #f5576c; font-family: 'Courier New', monospace; }
.message-type {
padding: 5px 10px;
border-radius: 5px;
font-size: 0.85em;
font-weight: 600;
text-align: center;
}
.type-std { background: #3498db; color: white; }
.type-ext { background: #9b59b6; color: white; }
.message-data { font-family: 'Courier New', monospace; color: #666; }
.message-interval { color: #888; font-size: 0.9em; }
.message-controls {
display: flex;
gap: 5px;
}
.btn-small {
padding: 5px 12px;
font-size: 0.85em;
}
h2 {
color: #333;
margin: 30px 0 20px 0;
padding-bottom: 10px;
border-bottom: 3px solid #f093fb;
}
.status-bar {
background: #2c3e50;
color: white;
padding: 10px 20px;
border-radius: 5px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.status-bar span { font-weight: 600; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📡 CAN Transmitter</h1>
<p>Send CAN Messages</p>
</div>
<div class="nav">
<a href="/">📊 Monitor</a>
<a href="/transmit" class="active">📡 Transmit</a>
</div>
<div class="content">
<div class="status-bar">
<span id="connection-status">🔴 Disconnected</span>
<span id="tx-count">Sent: 0 messages</span>
</div>
<h2> Add CAN Message</h2>
<div class="message-form">
<div class="form-row">
<div class="form-group">
<label>CAN ID (Hex)</label>
<input type="text" id="can-id" placeholder="123" maxlength="8">
</div>
<div class="form-group">
<label>Message Type</label>
<select id="msg-type">
<option value="std">Standard (11-bit)</option>
<option value="ext">Extended (29-bit)</option>
</select>
</div>
<div class="form-group">
<label>DLC</label>
<select id="dlc">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8" selected>8</option>
</select>
</div>
<div class="form-group">
<label>Interval (ms)</label>
<input type="number" id="interval" value="100" min="10" max="10000">
</div>
</div>
<div class="form-group" style="margin-bottom: 15px;">
<label>Data Bytes (Hex)</label>
<div class="data-bytes">
<input type="text" id="d0" placeholder="00" maxlength="2" value="00">
<input type="text" id="d1" placeholder="00" maxlength="2" value="00">
<input type="text" id="d2" placeholder="00" maxlength="2" value="00">
<input type="text" id="d3" placeholder="00" maxlength="2" value="00">
<input type="text" id="d4" placeholder="00" maxlength="2" value="00">
<input type="text" id="d5" placeholder="00" maxlength="2" value="00">
<input type="text" id="d6" placeholder="00" maxlength="2" value="00">
<input type="text" id="d7" placeholder="00" maxlength="2" value="00">
</div>
</div>
<div style="display: flex; gap: 10px;">
<button class="btn btn-primary" onclick="addMessage()"> Add to List</button>
<button class="btn btn-success" onclick="sendOnce()">📤 Send Once</button>
</div>
</div>
<h2>📋 Message List</h2>
<div style="margin-bottom: 15px; display: flex; gap: 10px;">
<button class="btn btn-success" onclick="startAll()"> Start All</button>
<button class="btn btn-danger" onclick="stopAll()"> Stop All</button>
<button class="btn btn-danger" onclick="clearAll()">🗑 Clear All</button>
</div>
<div class="message-list" id="message-list">
<p style="text-align: center; color: #666;">No messages added yet</p>
</div>
</div>
</div>
<script>
let ws;
let messages = [];
let txCount = 0;
function initWebSocket() {
ws = new WebSocket('ws://' + window.location.hostname + ':81');
ws.onopen = function() {
console.log('WebSocket connected');
document.getElementById('connection-status').innerHTML = '🟢 Connected';
};
ws.onclose = function() {
console.log('WebSocket disconnected');
document.getElementById('connection-status').innerHTML = '🔴 Disconnected';
setTimeout(initWebSocket, 3000);
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'txStatus') {
txCount = data.count;
document.getElementById('tx-count').textContent = 'Sent: ' + txCount + ' messages';
}
};
}
function addMessage() {
const id = document.getElementById('can-id').value.toUpperCase();
const type = document.getElementById('msg-type').value;
const dlc = parseInt(document.getElementById('dlc').value);
const interval = parseInt(document.getElementById('interval').value);
if (!id || !/^[0-9A-F]+$/.test(id)) {
alert('Invalid CAN ID! Use hex format (e.g., 123, 1A2)');
return;
}
const data = [];
for (let i = 0; i < 8; i++) {
const val = document.getElementById('d' + i).value.toUpperCase();
if (!/^[0-9A-F]{0,2}$/.test(val)) {
alert('Invalid data byte D' + i + '! Use hex format (00-FF)');
return;
}
data.push(val.padStart(2, '0'));
}
const msg = {
id: id,
type: type,
dlc: dlc,
data: data,
interval: interval,
active: false
};
messages.push(msg);
updateMessageList();
}
function sendOnce() {
const id = document.getElementById('can-id').value.toUpperCase();
const type = document.getElementById('msg-type').value;
const dlc = parseInt(document.getElementById('dlc').value);
const data = [];
for (let i = 0; i < 8; i++) {
data.push(document.getElementById('d' + i).value.toUpperCase().padStart(2, '0'));
}
sendCanMessage(id, type, dlc, data);
}
function sendCanMessage(id, type, dlc, data) {
const cmd = {
cmd: 'sendCan',
id: id,
type: type,
dlc: dlc,
data: data.join('')
};
ws.send(JSON.stringify(cmd));
console.log('Sent:', cmd);
}
function updateMessageList() {
const list = document.getElementById('message-list');
if (messages.length === 0) {
list.innerHTML = '<p style="text-align: center; color: #666;">No messages added yet</p>';
return;
}
list.innerHTML = '';
messages.forEach((msg, index) => {
const item = document.createElement('div');
item.className = 'message-item' + (msg.active ? ' active' : '');
item.innerHTML = `
<div class="message-id">0x${msg.id}</div>
<div class="message-type type-${msg.type}">${msg.type.toUpperCase()}</div>
<div class="message-data">${msg.data.slice(0, msg.dlc).join(' ')}</div>
<div class="message-interval">Every ${msg.interval}ms</div>
<div class="message-controls">
<button class="btn ${msg.active ? 'btn-danger' : 'btn-success'} btn-small"
onclick="toggleMessage(${index})">
${msg.active ? ' Stop' : ' Start'}
</button>
<button class="btn btn-danger btn-small" onclick="deleteMessage(${index})">
🗑
</button>
</div>
`;
list.appendChild(item);
});
}
function toggleMessage(index) {
messages[index].active = !messages[index].active;
const cmd = {
cmd: messages[index].active ? 'startMsg' : 'stopMsg',
index: index,
id: messages[index].id,
type: messages[index].type,
dlc: messages[index].dlc,
data: messages[index].data.join(''),
interval: messages[index].interval
};
ws.send(JSON.stringify(cmd));
updateMessageList();
}
function deleteMessage(index) {
if (messages[index].active) {
ws.send(JSON.stringify({cmd: 'stopMsg', index: index}));
}
messages.splice(index, 1);
updateMessageList();
}
function startAll() {
messages.forEach((msg, index) => {
if (!msg.active) {
toggleMessage(index);
}
});
}
function stopAll() {
ws.send(JSON.stringify({cmd: 'stopAll'}));
messages.forEach(msg => msg.active = false);
updateMessageList();
}
function clearAll() {
if (confirm('Clear all messages?')) {
stopAll();
messages = [];
updateMessageList();
}
}
// Hex input validation
document.querySelectorAll('input[id^="d"]').forEach(input => {
input.addEventListener('input', function() {
this.value = this.value.toUpperCase().replace(/[^0-9A-F]/g, '');
});
});
document.getElementById('can-id').addEventListener('input', function() {
this.value = this.value.toUpperCase().replace(/[^0-9A-F]/g, '');
});
initWebSocket();
</script>
</body>
</html>
)rawliteral";
#endif