-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.c
More file actions
236 lines (194 loc) · 8.78 KB
/
Copy pathmain.c
File metadata and controls
236 lines (194 loc) · 8.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// main.c
// RP2350RET main application
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/util/queue.h"
#include "tusb.h"
#include "bsp/board_api.h"
#include "common.h"
#include "xl2515_driver.h"
#include "gvret_protocol.h"
#include "serial_comm.h"
// バッファフラッシュ間隔 (2ms = 2000μs) - オリジナルGVRET互換
#define SER_BUFF_FLUSH_INTERVAL 2000
// グローバルキュー定義
queue_t rx_queue; // Core1 -> Core0
queue_t tx_queue; // Core0 -> Core1
// 定期フラッシュ用タイマー
static uint64_t lastFlushMicros = 0;
// CAN通信アクティビティフラグ(Core 1 で設定、Core 0 で参照)
volatile bool can_activity = false;
// コマンド応答送信中フラグ(CANデータとの混在を防ぐ)
volatile bool sending_command_response = false;
// Core 1: CANデバイス担当
void core1_entry(void) {
// XL2515初期化(xl2515_init()内で500kbps・Normalモードに設定済み)
bool can_available = xl2515_init();
// 初期化失敗時はエラーモード(USBは動作)
if (!can_available) {
// CAN不可でループ(送信キューのクリアのみ)
}
// アクティビティフラグを明示的にクリア
can_activity = false;
// CANフレームバッファ
can_frame_t frame;
// core1 main loop
while (true) {
if (can_available) {
// CAN受信をホスト側へキューイング
if (xl2515_receive(&frame)) {
// xl2515_receive()内で既にtimestamp設定済み
frame.isReceived = true;
// キューに追加(失敗時は破棄)
if (!queue_try_add(&rx_queue, &frame)) {
// キューが満杯:古いデータを破棄して新しいデータを追加
can_frame_t dummy;
queue_try_remove(&rx_queue, &dummy);
queue_try_add(&rx_queue, &frame);
}
can_activity = true; // CAN受信アクティビティ
}
// ホストからの送信要求をCANへ
if (queue_try_remove(&tx_queue, &frame)) {
frame.isReceived = false;
if (xl2515_send(&frame)) {
can_activity = true; // CAN送信アクティビティ
}
// 送信失敗時は黙って破棄(リトライなし)
}
} else {
// CAN未接続時は送信キューをクリア
queue_try_remove(&tx_queue, &frame);
}
sleep_us(10); // 短い待機でCPU負荷軽減(100→10μs)
}
}
int main(void) {
// LED初期化(デバッグ用)
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
// 起動確認:LED高速点滅3回
for (int i = 0; i < 3; i++) {
gpio_put(LED_PIN, 1);
sleep_ms(100);
gpio_put(LED_PIN, 0);
sleep_ms(100);
}
// 起動完了後は消灯(CAN通信検出時のみ点灯)
gpio_put(LED_PIN, 0);
// TinyUSBボード初期化
board_init();
tusb_init();
// ハードウェア初期化
serial_comm_init_uart();
// グローバルキュー初期化
queue_init(&rx_queue, sizeof(can_frame_t), CAN_BUFFER_SIZE);
queue_init(&tx_queue, sizeof(can_frame_t), CAN_BUFFER_SIZE);
// GVRETプロトコルハンドラー初期化
gvret_handler_t gvret;
gvret_response_t response = {0};
gvret_init(&gvret);
// USB列挙完了待機(最大2秒、短い間隔でポーリング)
for (int i = 0; i < 200; i++) {
tud_task();
if (tud_ready()) {
break;
}
sleep_ms(10); // 10msごとにチェック
}
// Core 1起動(CANデバイス担当)
multicore_launch_core1(core1_entry);
// Core1起動待機(XL2515初期化完了を待つ)
sleep_ms(20);
uint8_t usb_buf[64]; // USB受信バッファ
uint32_t last_can_activity = 0; // 最後のCANアクティビティ時刻
bool led_state = false; // 現在のLED状態
// core0 main loop
while (true) {
uint32_t now = to_ms_since_boot(get_absolute_time());
// TinyUSBデバイスタスク(必ず最初に呼び出す)
tud_task();
// CAN通信アクティビティインジケータ(LED制御)
if (can_activity) {
// CANアクティビティ検知:LED点灯し、最終アクティビティ時刻を更新
can_activity = false;
last_can_activity = now;
if (!led_state) {
gpio_put(LED_PIN, 1);
led_state = true;
}
}
// CAN通信が途絶えたらLED消灯(100ms無通信でタイムアウト)
if (led_state && (now - last_can_activity > 100)) {
gpio_put(LED_PIN, 0);
led_state = false;
}
// USB接続状態をチェック(接続時のみUSB処理を実行)
bool usb_connected = tud_ready() && tud_cdc_connected();
// USB -> GVRETパーサ(USB接続時のみ)
if (usb_connected) {
int read_len = serial_comm_usb_read(usb_buf, sizeof(usb_buf));
if (read_len > 0) {
// バイトごとに処理してレスポンスを取得
for (int i = 0; i < read_len; i++) {
if (gvret_process_byte(&gvret, usb_buf[i], &response)) {
// レスポンス送信
if (response.length > 0) {
// コマンド応答送信中フラグを設定(CANデータとの混在を防ぐ)
sending_command_response = true;
serial_comm_usb_write(response.data, response.length);
// コマンド応答は常に即座にflush(オリジナルGVRETと同様)
// これにより、複数コマンド応答が混在せず、個別のパケットとして送信される
tud_task();
tud_cdc_write_flush();
tud_task();
// フラッシュ完了を確実にするため、バッファが空になるまで待機
for (int wait = 0; wait < 10 && tud_cdc_write_available() < CFG_TUD_CDC_TX_BUFSIZE; wait++) {
tud_task();
sleep_us(100);
}
response.length = 0;
response.needs_immediate_flush = 0;
sending_command_response = false;
}
}
}
// 完成したCANフレームがあれば送信キューへ
if (gvret.frame_ready) {
gvret.build_frame.isReceived = false;
gvret.build_frame.timestamp = time_us_64();
queue_try_add(&tx_queue, &gvret.build_frame);
gvret.frame_ready = false;
}
}
} // USB接続時の処理ブロック終了
// CAN受信 -> USB + UART(USB接続に関係なく常に処理)
// コマンド応答送信中はCANデータの送信を抑制(パケット混在防止)
can_frame_t rx_frame;
if (!sending_command_response && queue_try_remove(&rx_queue, &rx_frame)) {
// タイムスタンプはCore1で記録済みのものを使用
// rx_frame.isReceivedもCore1で設定済み
gvret_format_can_frame(&gvret, &rx_frame, &response);
// USB送信(接続時のみ)- バッファリング
if (usb_connected && response.length > 0) {
serial_comm_usb_write(response.data, response.length);
}
// UART出力は常に実行(USB接続に関係なく)
serial_comm_uart_write_frame(&rx_frame);
response.length = 0;
}
// オリジナルGVRET方式: CANフレームの定期フラッシュ(2msごと)
uint64_t now_us = time_us_64();
if ((now_us - lastFlushMicros) >= SER_BUFF_FLUSH_INTERVAL) {
lastFlushMicros = now_us;
if (usb_connected) {
tud_task(); // USB処理
tud_cdc_write_flush(); // バッファ送出
}
}
// ループは最大速度で回し、tud_task()を頻繁に呼び出す
// sleepを入れるとUSB応答性が低下する
}
}