Documentation ¶
Overview ¶
Package lcm implements the serial communication protocol for the ASUSTOR LCD display. This includes controlling and updating and listening for button presses.
LCM data format:
MESSAGE_TYPE DATA_LENGTH FUNCTION [[DATA]...] [CRC]
Index ¶
- Constants
- func Scroll(line DisplayLine, text string) (next func() (raw Message, start, done bool))
- func ShowAllCharCodes() (next func() (line1, line2 Message, start, done bool), goBack func())
- type Button
- type DisplayLine
- type Function
- type LCM
- type Logger
- type Message
- type OpenOption
- type Power
- type Type
Constants ¶
const ( // DefaultReplyTimeout defines how long we wait for a reply, // usually one is received in under 10ms. We keep this timeout // fairly tight because a longer delay rarely helps. // // The ASUSTOR daemon resends messages after 100ms if no // response is received. But even this can leads to deadlocks // where the same error will be echoed back time and time again. DefaultReplyTimeout = 15 * time.Millisecond // DefaultRetryLimit defines how many times a command will be // retried until giving up. Given the default reply timeout, // this could lead to nothing happening on the screen for about // 750ms. // // ASUSTOR tries up to 100 times, however, this rarely helps // clear up the communication error. DefaultRetryLimit = 50 // DefaultWriteDelay defines how long to wait before writing the // next message. This is used both when writing commands and // responding to commands from the display. // // The ASUSTOR lcmd binary uses 15ms and 45ms sleeps between // certain commands, but this seems excessive. DefaultWriteDelay = 250 * time.Microsecond )
const DefaultTTY = "/dev/ttyS1"
DefaultTTY represents the default serial tty for LCM.
Variables ¶
This section is empty.
Functions ¶
func Scroll ¶
func Scroll(line DisplayLine, text string) (next func() (raw Message, start, done bool))
Scroll the text on the display. Each invocation of next() will return a message to send. The start value indicates that the text is in the starting position and the done value indicates one rotation has completed. Done becomes true one step before start meaning that the starting position is not yet reached (we have scrolled to the end).
next := lcm.Scroll(lcm.DisplayTop, "This text will scroll") for { b, start, done := next() send(m, b) if start { time.Sleep(2 * time.Second) } else { time.Sleep(1 * time.Second) } if start && done { break } }
func ShowAllCharCodes ¶
ShowAllCharCodes allows all character codes to be
Types ¶
type DisplayLine ¶
type DisplayLine int
DisplayLine specifies which line to write the text on.
const ( DisplayTop DisplayLine = iota DisplayBottom )
DisplayLine enums.
type LCM ¶
type LCM struct {
// contains filtered or unexported fields
}
LCM represents the ASUSTOR Liquid Crystal Monitor.
func Open ¶
func Open(tty string, opt ...OpenOption) (*LCM, error)
Open opens the serial port for LCM.
type Logger ¶
type Logger interface {
Printf(format string, v ...interface{})
}
Logger represents a generic logger (e.g. from the log package).
type Message ¶
type Message []byte
Message represents a serial port message with common bits easily accessible.
var ( // DisplayOn turns the display on. DisplayOn Message = []byte{byte(Command), 0x01, byte(Fon), 0x01} // DisplayOff turns the display off. DisplayOff Message = []byte{byte(Command), 0x01, byte(Fon), 0x00} // ClearDisplay clears the current text from the display. // Called during re-initialization in lcmd. ClearDisplay Message = []byte{byte(Command), 0x01, byte(Fclear), 0x01} // ClearDisplayPrefix clears the screen and its behavior is // altered by AlterClearDisplayPrefix. // // It is unused in lcmd. ClearDisplayPrefix Message = []byte{byte(Command), 0x01, byte(Fclear2), 0x00} // DisplayStatus has an unknown purpose. It is issued after // DisplayOn in the init-routine and sometimes before/after // updating the text. // // It could have some other purpose, like SetClearDisplayPrefix. DisplayStatus Message = []byte{byte(Command), 0x01, byte(Fstatus), 0x00} // RequestVersion reports the MCU version via command. // The only observed version number so far is 0.1.2 on both // AS604T and AS6204T. // // Note: Issuing this request takes 200+ms and acknowledging // that we received the message often results in the display // thinking we re-requested the version. ASUSTOR does not seem // to use this, perhaps there is only one version out there. // // => 0xf001130105 // <= 0xf101130005 (ack) // <= 0xf0031300010209 (version) RequestVersion Message = []byte{byte(Command), 0x01, byte(Fversion), 0x01} )
Known commands (for sending to display).
var ( // UnknownReply0x10, unused in the lcmd binary. We don't know // the purpose of the 0x10 function, but it may be possible for // the display to issue this command, in which case this would // be the (error) response. UnknownReply0x10 Message = []byte{byte(Reply), 0x01, 0x10, 0x02} // UnknownReply0x10, unused in the lcmd binary. This is an error // reply issued by the display as a response to the On function, // however, it's purpose in the lcmd binary is unknown. UnknownReply0x11 Message = []byte{byte(Reply), 0x01, byte(Fon), 0x02} )
Replies are acknowledgements to commands, when the payload bit is zero, the command was successfully received (and applied), when it's non-zero, there was an error.
We don't know exactly what the different non-zero bits mean other than an error occurred. The bits are usually either 0x02 or 0x04, but even ASUSTORs lcmd binary does not care, it simply re-issues commands on any non-zero bit.
Documented here are some mysteries found in the lcmd binary.
UnknownCommand0x23, unused. Values come from function arguments.
Observed behavior: Nothing.
func SetClearDisplayPrefix ¶
SetClearDisplayPrefix changes the behavior of ClearDisplayPrefix.
Known values and behavior of ClearDisplayPrefix: * 0 = Clear screen (fully) * 1 = Clear screen with underscore * 2 = Clear screen, blink between underscore and block
In lcmd this command is sometimes used after the text for line 0 has been set and before line 1 is cleared with spaces. Unless it has other unobserved behaviors, it's probably unused in practice.
func SetDisplay ¶
func SetDisplay(line DisplayLine, indent int, text string) (raw Message, err error)
SetDisplay allows 16 characters to be written on either the top or bottom line, and indent can be used in which case not all characters in the message will be visible.
When using indent, it's a good idea to fill the display with spaces before (first) use so that there is no stray characters in the beginning. This can be achieved by first setting the display to the empty string as it will be padded with spaces.
SetDisplay(DisplayTop, 0, "") SetDisplay(DisplayTop, 2, "My message")
func SetDisplayCharacter ¶
func SetDisplayCharacter(line DisplayLine, column int, char byte) (Message, error)
SetDisplayCharacter writes a single character onto the display in the specificed location.
In lcmd, it is used by Lcmd_User_Menu_Ctl.
type OpenOption ¶
type OpenOption func(*openOptions)
OpenOption configures LCM during open.
func EnableProtocolAckReply ¶
func EnableProtocolAckReply() OpenOption
EnableProtocolAckReply specifies if LCM should send acknowledgement replies to the screen when it sends us a command (e.g. button press or firmware version).
If the screen sent us a command, technically we should acknowledge it by sending a reply indicating it was successful. However, it often causes later commands (from us) to become corrupt. The frequency of the corruption can be lowered with delays, but then again, it seems like the display does not care if we reply or not.
func WithLogger ¶
func WithLogger(l Logger) OpenOption
WithLogger sets the logger used by LCM (default none).
type Power ¶
type Power struct {
// contains filtered or unexported fields
}
Power management via GPIO line.
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
lcm-monitor
lcm-monitor intercepts the communication between the ASUSTOR LCD daemon (lcmd) and the LCD display and saves the input (from LCD) and output (from lcmd) to files.
|
lcm-monitor intercepts the communication between the ASUSTOR LCD daemon (lcmd) and the LCD display and saves the input (from LCD) and output (from lcmd) to files. |