626 lines
17 KiB
C
626 lines
17 KiB
C
/*
|
|
* Copyright (C) 2010 Apple Inc. All rights reserved.
|
|
*
|
|
* This document is the property of Apple Inc.
|
|
* It is considered confidential and proprietary.
|
|
*
|
|
* This document may not be reproduced or transmitted in any form,
|
|
* in whole or in part, without the express written permission of
|
|
* Apple Inc.
|
|
*/
|
|
|
|
#include <debug.h>
|
|
#include <sys/menu.h>
|
|
#include <sys/task.h>
|
|
#include <drivers/mcu.h>
|
|
#include <drivers/uart.h>
|
|
#include <target/uartconfig.h>
|
|
#include <limits.h>
|
|
|
|
// TI MSP430F2350 MCU Serial Packet Format
|
|
//
|
|
// 0 1
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +0
|
|
// | 'S' | 't' |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +2
|
|
// | OpCode | Seq No |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +4
|
|
// | Length High | Length Low |
|
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +6
|
|
// | |
|
|
// | <payload> |
|
|
// | |
|
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
|
// | CRC-16 High | CRC-16 Low |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
// Sequence number is even for MCU->CPU packets and odd for CPU->MCU packets.
|
|
// CRC is a CRC-16 CCITT (polynomial 0x1021, init value is 0xFFFF).
|
|
|
|
typedef uint8_t MCUOpCode;
|
|
|
|
// Commands requiring acks.
|
|
|
|
#define kMCUOpCode_NoOp 0x00
|
|
#define kMCUOpCode_PowerOnReset 0x01
|
|
#define kMCUOpCode_GetVersion 0x02 // Response: <2:major>.<2:minor>[.<4:revision>]
|
|
#define kMCUOpCode_SILControl 0x04 // Request: <1:action>
|
|
|
|
#define kMCUSILAction_Invalid 0xFF
|
|
|
|
#define kMCUSILAction_Off 0
|
|
#define kMCUSILAction_OffStr "off"
|
|
|
|
#define kMCUSILAction_On 1
|
|
#define kMCUSILAction_OnStr "on"
|
|
|
|
#define kMCUSILAction_SlowFlash 2
|
|
#define kMCUSILAction_SlowStr "slow"
|
|
|
|
#define kMCUSILAction_FastFlash 3
|
|
#define kMCUSILAction_FastStr "fast"
|
|
|
|
#define kMCUSILAction_1Blink 4
|
|
#define kMCUSILAction_1BlinkStr "1blink"
|
|
|
|
#define kMCUSILAction_3Blinks 5
|
|
#define kMCUSILAction_3BlinksStr "3blinks"
|
|
|
|
#define kMCUOpCode_PairControl 0x05 // Request: <1:0=unpair, 1=pair> <1:remote UID>
|
|
|
|
#define kMCUPairAction_Unpair 0x00
|
|
#define kMCUPairAction_Pair 0x01
|
|
|
|
#define kMCUOpCode_BlueSteelControl 0x06 // Request: <1:mode> <1:subMode>
|
|
|
|
#define kMCUBSControl_Invalid 0xff
|
|
|
|
#define kMCUBSControl_Reset 0
|
|
#define kMCUBSControl_ResetStr "reset"
|
|
#define kMCUBSControl_EnterTestMode 1
|
|
#define kMCUBSControl_EnterTestModeStr "testmode"
|
|
#define kMCUBSControl_PassthroughMode 2
|
|
#define kMCUBSControl_PassthroughModeStr "passthru"
|
|
#define kMCUBSControl_InfoFrameEnable 5
|
|
#define kMCUBSControl_InfoFrameEnableStr "info"
|
|
|
|
#define kMCUOpCode_SystemState 0x07 // Request: <1:state>
|
|
|
|
#define kMCUSystemState_NoChange 0x00
|
|
#define kMCUSystemState_Standby 0x01
|
|
#define kMCUSystemState_Normal 0x02
|
|
|
|
#define kMCUOpCode_AppleIRData 0x10
|
|
#define kMCUOpCode_Repeat 0x11
|
|
#define kMCUOpCode_3rdPartyIRData 0x12
|
|
|
|
// Acks to commands.
|
|
|
|
#define kMCUOpCode_Ack 0x80
|
|
#define kMCUOpCode_NakUnknown 0x81
|
|
#define kMCUOpCode_NakUnsupported 0x82
|
|
#define kMCUOpCode_NakBadCRC 0x83
|
|
#define kMCUOpCode_NakNotNow 0x84
|
|
#define kMCUOpCode_NakMessageTooLong 0x85
|
|
#define kMCUOpCode_NakOther 0x9F
|
|
|
|
#define MCUOpCode_IsAckOrNak( X ) \
|
|
( ( (X) == kMCUOpCode_Ack ) || \
|
|
( (X) == kMCUOpCode_NakUnknown ) || \
|
|
( (X) == kMCUOpCode_NakUnsupported ) || \
|
|
( (X) == kMCUOpCode_NakBadCRC ) || \
|
|
( (X) == kMCUOpCode_NakNotNow ) || \
|
|
( (X) == kMCUOpCode_NakMessageTooLong ) || \
|
|
( (X) == kMCUOpCode_NakOther ) )
|
|
|
|
// No response necessary.
|
|
|
|
#define kMCUOpCode_DebugData 0xFF
|
|
|
|
// Set to 1 to print text contents of MCU debug packets
|
|
#define PRINT_MCU_DEBUG 0
|
|
|
|
// Constants
|
|
|
|
#define kMCUResponseTimeout 4000000
|
|
#define kMCUTaskStackSize 8192
|
|
#define kMCUMaxRecvSize 32
|
|
|
|
#define kMCUBaudRate 250000
|
|
#define kMCUWordPeriodUS (1000000 / (kMCUBaudRate/10))
|
|
#define kMCUFifoSize 1024
|
|
|
|
#define kMCUNotNowDelayUS 100000
|
|
#define kMCUNotNowAttempts 100
|
|
#define kMCUReadTimeoutUS 1000000
|
|
#define kMCUSendAttempts 5
|
|
|
|
#define kMCUFifoLatencyUS (kMCUWordPeriodUS * kMCUFifoSize)
|
|
#define kMCUReadSleepUS (kMCUFifoLatencyUS / 4)
|
|
|
|
struct McuRecvPacket {
|
|
uint8_t opcode;
|
|
uint8_t buf[kMCUMaxRecvSize];
|
|
size_t len;
|
|
};
|
|
|
|
static bool gIsMCUInitialized = false;
|
|
static struct task_event mcu_gate;
|
|
static struct task_event mcu_packet_arrived;
|
|
static struct task_event mcu_packet_consumed;
|
|
static bool mcu_recv_valid;
|
|
static struct McuRecvPacket mcu_recv;
|
|
|
|
static int mcu_send_command(int opcode, uint8_t *data, size_t data_len);
|
|
static int mcu_set_sil(int action);
|
|
static int mcu_set_bs(int data0, int data1); // data1 == -1 if unused.
|
|
static int mcu_get_version(char *version, size_t length);
|
|
|
|
static int mcu_task(void *arg);
|
|
static int mcu_send_packet(MCUOpCode opcode, uint8_t *data, size_t length);
|
|
static int mcu_read_packet(MCUOpCode *outOpcode, uint8_t *outData, size_t maxLen, size_t *outLen);
|
|
static int mcu_read_response(MCUOpCode *outOpcode, uint8_t *outData, size_t maxLen, size_t *outLen);
|
|
static unsigned long crc_ccitt(unsigned long crc, unsigned char* p, unsigned long len);
|
|
|
|
int mcu_init(void)
|
|
{
|
|
int ret = -1;
|
|
char version[kMCUMaxRecvSize];
|
|
|
|
uart_hw_init_extended(MCU_SERIAL_PORT, kMCUBaudRate, 8, PARITY_NONE, 1);
|
|
ret = uart_hw_set_rx_buf(MCU_SERIAL_PORT, true, kMCUFifoSize);
|
|
if (ret != 0) panic("mcu_init() uart_hw_set_rx_buf failed");
|
|
|
|
// send break to resync stream
|
|
uart_send_break(MCU_SERIAL_PORT, true);
|
|
task_sleep(kMCUWordPeriodUS * 2); // at least one word
|
|
uart_send_break(MCU_SERIAL_PORT, false);
|
|
|
|
event_init(&mcu_gate, EVENT_FLAG_AUTO_UNSIGNAL, true);
|
|
event_init(&mcu_packet_arrived, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
|
event_init(&mcu_packet_consumed, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
|
task_start(task_create("mcu", &mcu_task, NULL, kMCUTaskStackSize));
|
|
|
|
// first, retrieve MCU version string
|
|
ret = mcu_get_version(version, sizeof(version));
|
|
|
|
// constant slow-blink: device is booting
|
|
if (ret == 0) {
|
|
ret = mcu_set_sil(kMCUSILAction_SlowFlash);
|
|
}
|
|
|
|
// record and report whether MCU was successfully initialized
|
|
gIsMCUInitialized = (ret == 0);
|
|
if (gIsMCUInitialized) {
|
|
dprintf(DEBUG_INFO, "MCU version: %s\n", version);
|
|
} else {
|
|
dprintf(DEBUG_CRITICAL, "mcu_init() failed\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mcu_start_recover(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
event_wait(&mcu_gate);
|
|
// constant fast-blink: plug into iTunes
|
|
if (gIsMCUInitialized) {
|
|
ret = mcu_set_sil(kMCUSILAction_FastFlash);
|
|
}
|
|
event_signal(&mcu_gate);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mcu_start_boot(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
event_wait(&mcu_gate);
|
|
// constant slow-blink: device is booting
|
|
if (gIsMCUInitialized) {
|
|
ret = mcu_set_sil(kMCUSILAction_SlowFlash);
|
|
}
|
|
event_signal(&mcu_gate);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mcu_set_passthrough_mode(bool on)
|
|
{
|
|
int ret = -1;
|
|
|
|
if (gIsMCUInitialized) {
|
|
event_wait(&mcu_gate);
|
|
if (on) {
|
|
ret = mcu_set_bs(kMCUBSControl_EnterTestMode, -1);
|
|
if (ret != 0) goto exit;
|
|
ret = mcu_set_bs(kMCUBSControl_PassthroughMode, -1);
|
|
if (ret != 0) goto exit;
|
|
} else {
|
|
ret = mcu_set_bs(kMCUBSControl_Reset, -1);
|
|
}
|
|
exit:
|
|
if (ret != 0) {
|
|
dprintf(DEBUG_CRITICAL, "mcu_set_passthrough_mode %d failed\n", on);
|
|
}
|
|
event_signal(&mcu_gate);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mcu_send_info_frames(bool on)
|
|
{
|
|
int ret = -1;
|
|
|
|
if (gIsMCUInitialized) {
|
|
event_wait(&mcu_gate);
|
|
ret = mcu_set_bs(kMCUBSControl_InfoFrameEnable, on ? 1 : 0);
|
|
event_signal(&mcu_gate);
|
|
if (ret != 0) {
|
|
dprintf(DEBUG_CRITICAL, "mcu_send_info_farmes %d failed\n", on);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mcu_quiesce_uart(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = uart_hw_set_rx_buf(MCU_SERIAL_PORT, false, kMCUFifoSize);
|
|
if (ret != 0)
|
|
panic("uart can not be put into polling mode!");
|
|
return ret;
|
|
}
|
|
static int mcu_send_command(int command, uint8_t *data, size_t data_len)
|
|
{
|
|
int retries = kMCUSendAttempts;
|
|
int not_now_retries = kMCUNotNowAttempts;
|
|
int ret = -1;
|
|
|
|
do {
|
|
ret = mcu_send_packet(command, data, data_len);
|
|
if (ret != 0) continue;
|
|
|
|
uint8_t opcode;
|
|
ret = mcu_read_response(&opcode, NULL, 0, NULL);
|
|
if (ret != 0) continue;
|
|
if (opcode != kMCUOpCode_Ack) ret = -1;
|
|
if (opcode == kMCUOpCode_NakNotNow) {
|
|
// MCU isn't in the right state for this command. Allow
|
|
// more time than usual for this transient state to pass.
|
|
if (--not_now_retries > 0) {
|
|
task_sleep(kMCUNotNowDelayUS);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} while ((ret != 0) && (--retries > 0));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mcu_set_sil(int action)
|
|
{
|
|
uint8_t data = action;
|
|
return mcu_send_command(kMCUOpCode_SILControl, &data, 1);
|
|
}
|
|
|
|
static int mcu_set_bs(int data0, int data1)
|
|
{
|
|
uint8_t buf[2] = { data0, data1 };
|
|
return mcu_send_command(kMCUOpCode_BlueSteelControl, buf, data1 >= 0 ? 2 : 1);
|
|
}
|
|
|
|
static int mcu_get_version(char *version, size_t length)
|
|
{
|
|
int ret;
|
|
|
|
ret = mcu_send_packet(kMCUOpCode_GetVersion, NULL, 0);
|
|
if (ret != 0) return ret;
|
|
|
|
uint8_t opcode;
|
|
size_t outLength;
|
|
ret = mcu_read_response(&opcode, (uint8_t *)version, length, &outLength);
|
|
if (ret != 0) return ret;
|
|
if (opcode != kMCUOpCode_Ack) return -1;
|
|
|
|
if (version) version[outLength-1] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mcu_task(void *arg)
|
|
{
|
|
struct McuRecvPacket new_recv;
|
|
bzero(&new_recv, sizeof(new_recv));
|
|
for (;;) {
|
|
int ret = mcu_read_packet(&new_recv.opcode,
|
|
new_recv.buf,
|
|
sizeof(new_recv.buf),
|
|
&new_recv.len);
|
|
if (ret != 0) continue;
|
|
// Process uninteresting packets here.
|
|
if (new_recv.opcode == kMCUOpCode_DebugData) {
|
|
#if PRINT_MCU_DEBUG
|
|
size_t i;
|
|
dprintf(DEBUG_INFO, "mcu: \"");
|
|
for (i = 0; i < new_recv.len; ++i)
|
|
dprintf(DEBUG_INFO, "%c", new_recv.buf[i]);
|
|
dprintf(DEBUG_INFO, "\"\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
if (!MCUOpCode_IsAckOrNak(new_recv.opcode)) continue;
|
|
// Signal packet arrival.
|
|
memcpy(&mcu_recv, &new_recv, sizeof(mcu_recv));
|
|
mcu_recv_valid = true;
|
|
event_signal(&mcu_packet_arrived);
|
|
// Wait for packet consumption.
|
|
while (mcu_recv_valid) {
|
|
event_wait(&mcu_packet_consumed);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int mcu_send_packet(MCUOpCode opcode, uint8_t *payload, size_t length)
|
|
{
|
|
if (length > 0xFFFF) return -1;
|
|
|
|
uint16_t crc = 0xffff;
|
|
uint8_t header[6] = { 'S', 't', opcode, 0x01, (length >> 8) & 0xFF, length & 0xFF };
|
|
|
|
dprintf(DEBUG_SPEW, "mcu_send_packet 0x%02x\n", opcode);
|
|
|
|
for (unsigned i = 0; i < sizeof(header); i++) {
|
|
uart_putc(MCU_SERIAL_PORT, header[i]);
|
|
}
|
|
for (unsigned i = 0; i < length; i++) {
|
|
uart_putc(MCU_SERIAL_PORT, payload[i]);
|
|
}
|
|
|
|
crc = crc_ccitt(crc, header, sizeof(header));
|
|
crc = crc_ccitt(crc, payload, length);
|
|
|
|
uart_putc(MCU_SERIAL_PORT, (crc >> 8) & 0xFF);
|
|
uart_putc(MCU_SERIAL_PORT, crc & 0xFF);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mcu_read_response(MCUOpCode *outOpcode, uint8_t *outData, size_t maxLen, size_t *outLen)
|
|
{
|
|
// wait at most a second
|
|
utime_t timeout = system_time() + kMCUResponseTimeout;
|
|
|
|
// Wait for a packet.
|
|
while (!mcu_recv_valid) {
|
|
utime_t now = system_time();
|
|
if (now >= timeout) {
|
|
dprintf(DEBUG_INFO, "mcu response timeout\n");
|
|
return -1;
|
|
}
|
|
event_wait_timeout(&mcu_packet_arrived, timeout - now);
|
|
}
|
|
|
|
dprintf(DEBUG_SPEW, "received mcu packet type %#x\n", mcu_recv.opcode);
|
|
if (outOpcode != NULL) *outOpcode = mcu_recv.opcode;
|
|
if (outData) memcpy(outData, mcu_recv.buf, maxLen < mcu_recv.len ? maxLen : mcu_recv.len);
|
|
if (outLen) *outLen = mcu_recv.len;
|
|
if (mcu_recv.len > maxLen) {
|
|
dprintf(DEBUG_SPEW, "mcu packet exceeds maxLen (%d vs %d)\n",
|
|
(int) mcu_recv.len, (int) maxLen);
|
|
}
|
|
mcu_recv_valid = false;
|
|
event_signal(&mcu_packet_consumed);
|
|
return 0;
|
|
}
|
|
|
|
static int mcu_read_packet(MCUOpCode *outOpcode, uint8_t *outData, size_t maxLen, size_t *outLen)
|
|
{
|
|
utime_t timeout = system_time() + kMCUReadTimeoutUS;
|
|
int ret = -1;
|
|
size_t offset = 0;
|
|
size_t length = 0;
|
|
uint16_t crc = 0xffff;
|
|
|
|
for (;;) {
|
|
int ch;
|
|
for (;;) {
|
|
ch = uart_getc(MCU_SERIAL_PORT, false);
|
|
if (ch >= 0) break;
|
|
if (system_time() >= timeout) goto exit;
|
|
task_sleep(kMCUReadSleepUS);
|
|
}
|
|
|
|
if (offset == 0) {
|
|
if (ch != 'S') continue;
|
|
} else if (offset == 1) {
|
|
if (ch != 't') {
|
|
offset = (ch == 'S') ? 1 : 0;
|
|
continue;
|
|
}
|
|
} else if (offset == 2) {
|
|
if (outOpcode != NULL) *outOpcode = ch;
|
|
} else if (offset == 3) {
|
|
// ignore sequence number
|
|
} else if (offset == 4) {
|
|
length = (ch & 0xFF) << 8;
|
|
} else if (offset == 5) {
|
|
length |= (ch & 0xFF);
|
|
} else if (offset < (length + 6)) {
|
|
if ((maxLen + 6) > offset) {
|
|
outData[offset-6] = ch;
|
|
}
|
|
} else if ((offset - (length + 6)) == 0) {
|
|
if (((crc >> 8) & 0xFF) != ch) {
|
|
dprintf(DEBUG_INFO, "mcu checksum failure\n");
|
|
goto exit;
|
|
}
|
|
} else if ((offset - (length + 6)) == 1) {
|
|
if ((crc & 0xFF) != ch) {
|
|
dprintf(DEBUG_INFO, "mcu checksum failure\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (outLen != NULL) *outLen = (maxLen < length) ? maxLen : length;
|
|
ret = 0;
|
|
goto exit;
|
|
}
|
|
|
|
if (offset < (length + 6)) {
|
|
uint8_t b = ch;
|
|
crc = crc_ccitt(crc, &b, sizeof(b));
|
|
}
|
|
offset++;
|
|
}
|
|
|
|
dprintf(DEBUG_INFO, "mcu read timeout\n");
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
const int order = 16;
|
|
const unsigned long polynom = 0x1021;
|
|
|
|
static unsigned long crc_ccitt(unsigned long crc, unsigned char* p, unsigned long len)
|
|
{
|
|
// fast bit by bit algorithm without augmented zero bytes.
|
|
// does not use lookup table, suited for polynom orders between 1...32.
|
|
|
|
unsigned long i, j, c, bit;
|
|
|
|
unsigned long crchighbit = (unsigned long)1<<(order-1);
|
|
|
|
for (i=0; i<len; i++) {
|
|
|
|
c = (unsigned long)*p++;
|
|
|
|
for (j=0x80; j; j>>=1) {
|
|
|
|
bit = crc & crchighbit;
|
|
crc<<= 1;
|
|
if (c & j)
|
|
bit ^= crchighbit;
|
|
if (bit)
|
|
crc ^= polynom;
|
|
}
|
|
}
|
|
|
|
return crc;
|
|
}
|
|
|
|
#if WITH_MENU
|
|
|
|
static int mcu_send_raw(int command, uint8_t *data, int data_len)
|
|
{
|
|
int ret;
|
|
uint8_t opcode;
|
|
ret = mcu_send_packet(command, data, data_len);
|
|
if (ret != 0) {
|
|
printf("mcu_send_packet failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
ret = mcu_read_response(&opcode, NULL, 0, NULL);
|
|
if (ret != 0) {
|
|
printf("mcu_read_response failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mcu(int argc, struct cmd_arg *args)
|
|
{
|
|
if (!gIsMCUInitialized) {
|
|
if (0 == mcu_init()) {
|
|
printf("WARNING: mcu not previously initialized");
|
|
} else {
|
|
printf("ERROR: unable to initialize mcu");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if ((argc > 1) && !strcmp(args[1].str, "version"))
|
|
{
|
|
char version[32];
|
|
if (mcu_get_version(version, sizeof(version)) == 0) {
|
|
printf("%s\n", version);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if ((argc > 2) && !strcmp(args[1].str, "sil"))
|
|
{
|
|
int action = kMCUSILAction_Invalid;
|
|
|
|
if (!strcmp(args[2].str, kMCUSILAction_OffStr)) action = kMCUSILAction_Off;
|
|
else if (!strcmp(args[2].str, kMCUSILAction_OnStr)) action = kMCUSILAction_On;
|
|
else if (!strcmp(args[2].str, kMCUSILAction_SlowStr)) action = kMCUSILAction_SlowFlash;
|
|
else if (!strcmp(args[2].str, kMCUSILAction_FastStr)) action = kMCUSILAction_FastFlash;
|
|
else if (!strcmp(args[2].str, kMCUSILAction_1BlinkStr)) action = kMCUSILAction_1Blink;
|
|
else if (!strcmp(args[2].str, kMCUSILAction_3BlinksStr)) action = kMCUSILAction_3Blinks;
|
|
|
|
if (action != kMCUSILAction_Invalid)
|
|
{
|
|
return mcu_set_sil(action);
|
|
}
|
|
}
|
|
|
|
if ((argc > 2) && !strcmp(args[1].str, "bs"))
|
|
{
|
|
int action = kMCUBSControl_Invalid;
|
|
int extra = -1;
|
|
|
|
if (!strcmp(args[2].str, kMCUBSControl_ResetStr)) action = kMCUBSControl_Reset;
|
|
else if (!strcmp(args[2].str, kMCUBSControl_EnterTestModeStr)) action = kMCUBSControl_EnterTestMode;
|
|
else if (!strcmp(args[2].str, kMCUBSControl_PassthroughModeStr)) action = kMCUBSControl_PassthroughMode;
|
|
else if (!strcmp(args[2].str, kMCUBSControl_InfoFrameEnableStr) && argc > 3) {
|
|
action = kMCUBSControl_InfoFrameEnable;
|
|
extra = args[3].u;
|
|
}
|
|
|
|
if (action != kMCUBSControl_Invalid)
|
|
{
|
|
return mcu_set_bs(action, extra);
|
|
}
|
|
|
|
}
|
|
|
|
if ((argc > 2) && !strcmp(args[1].str, "raw"))
|
|
{
|
|
int i;
|
|
uint8_t command = args[2].u;
|
|
uint8_t data[8];
|
|
size_t data_len = argc - 3;
|
|
if (data_len > sizeof(data)) {
|
|
printf("Max %zu raw bytes\n", sizeof(data) + 1);
|
|
return -1;
|
|
}
|
|
for (i = 3; i < argc; ++i) data[i - 3] = args[i].u;
|
|
return mcu_send_raw(command, data, data_len);
|
|
}
|
|
|
|
printf("%s version\n", args[0].str);
|
|
printf("%s sil [%s|%s|%s|%s|%s|%s]\n", args[0].str,
|
|
kMCUSILAction_OffStr, kMCUSILAction_OnStr, kMCUSILAction_SlowStr, kMCUSILAction_FastStr,
|
|
kMCUSILAction_1BlinkStr, kMCUSILAction_3BlinksStr);
|
|
printf("%s bs [%s|%s|%s|%s]\n", args[0].str,
|
|
kMCUBSControl_ResetStr, kMCUBSControl_EnterTestModeStr, kMCUBSControl_PassthroughModeStr, kMCUBSControl_InfoFrameEnableStr);
|
|
printf("%s raw <byte> ...\n", args[0].str);
|
|
|
|
return -1;
|
|
}
|
|
|
|
MENU_COMMAND_DEVELOPMENT(mcu, do_mcu, "MCU control", NULL);
|
|
|
|
#endif
|