Jump to content

Recommended Posts

Posted

I'm trying to get the Lego Technic CyberMaster C2 (8482-1) working on my Mac using Swift.

I've lost the original cable and have no idea about wiring or protocol.

I can make the transmitter "blink" using a null modem cable but nothing is received on the receiver.

Does anyone happen to know if the RS232 serial cable specs are documented anywhere?

Has anyone already reverse engineered the protocol?

It's a tricky one because I'm not sure if it's:


a) My dodgy cable
b) My dodgy code
c) My USB to Serial adapter

...that's causing the issue.

Any tips or tricks? Thanks team!

IMG_9229 Large Small.jpeg

Posted

One tip could be to use Wireshark. It can also capture USB. Also Claude or another LLM would be of great help! First get the protocol then it is relatively easy to make a Swift app around it.

Posted
On 7/4/2025 at 1:49 AM, Chris Hocking said:

I can make the transmitter "blink" using a null modem cable but nothing is received on the receiver.

Hi Chris,

1) what are you sending via the serial port at 2) what Baud rate/data bits/parity setting?

About the protocol(s):

  1. The close to hardware protocol is 2400 baud, 8 data bits, odd parity. Null modem cable is fine. 
  2. The close to software protocol is "LEGO byte code", as used by LEGO software for the RCX, SCOUT, Spybots, Cybermaster programmable bricks (PBricks), as well as by NQC/BricxCC. There is nice documentation about that - maybe I can dig that up (again ;) @Carsten Svendsen has referenced a thread that maybe helpful, here is another one - go to the RCX etc. section further down:
    LEGO byte code is essentially an opcode sometimes followed by data bytes. These individual bytes are wrapped with some more byte (called 3-byte preamble, then data byte, complement of data byte etc. etc. As said, this protocol is the same for the referenced PBricks above.

Any chance you can run BricxCC/NQC on your Mac? In that case, you would have full access to the Cybermaster (CM) PBrick (direct control and programming). The NQC documentation tells you all about LEGO byte codes and which one are available on the CM.

Best regards and good luck!
Thorsten

 

Posted

Thanks everyone for your replies - HUGELY appreciated!

I have skimmed through most of those posts I think - I've basically read most things that "Cybermaster" returns on Google, haha.

I was unsure about the cable, so I've tried both a null modem cable and re-wiring it to be a straight-through cable. When using a null modem cable, the LED on the transmitter lights up, whereas with the straight-through wiring it does now. Good to know that a null modem cable should be fine - thanks Thorsten!

At home I currently only have access to a Mac, but I do have a PC in the office which I can try next week. I'll try installing 
Bricx Command Center (BricxCC) on the PC.

I have tried two different USB to Serial adapters:

USB-Serial Controller :

  Product ID:    0x23a3
  Vendor ID:    0x067b  (Prolific Technology, Inc.)
  Version:    6.05
  Serial Number:    CVDYf146B11
  Speed:    Up to 12 Mb/s
  Manufacturer:    Prolific Technology Inc. 
  Location ID:    0x00100000 / 1
  Current Available (mA):    500
  Current Required (mA):    100
  Extra Operating Current (mA):    0
USB HS Serial Converter:

  Product ID:    0x6001
  Vendor ID:    0x0403  (Future Technology Devices International Limited)
  Version:    4.00
  Serial Number:    FTC87U6C
  Speed:    Up to 12 Mb/s
  Manufacturer:    FTDI
  Location ID:    0x00120000 / 3
  Current Available (mA):    500
  Current Required (mA):    44
  Extra Operating Current (mA):    0

I'm currently using these port settings in Swift code:

func openPort() {
    guard let port = selectedPort else { return }
    port.baudRate = 9600
    port.numberOfStopBits = 1
    port.parity = .odd
    port.numberOfDataBits = 8
    port.usesRTSCTSFlowControl = false
    port.usesDTRDSRFlowControl = false        
    port.dtr = true
    port.rts = true
    port.delegate = self
    port.open()
}

Based on Thorsten's notes - I'll try changing baud rate, etc.

I'm currently using this Swift code for the packet data:

/// Build a CyberMaster packet
func cyberMasterPacket(cmd: UInt8, data: [UInt8]) -> [UInt8] {
    let stx: UInt8 = 0x02
    let etx: UInt8 = 0x03
    let len = UInt8(1 + data.count + 1)          // CMD + data + checksum
    var pkt  = [stx, len, cmd] + data
    let chk  = pkt[1...].reduce(0, ^)            // XOR LEN,CMD,DATA…
    pkt += [chk, etx]
    return pkt
}

enum CyberMasterOutput: UInt8 { case left=0, right, black }
enum CyberMasterDirection: UInt8 { case forward=0x7F, backward=0x81, off=0x00 }

func outputPacket(channel: UInt8,
                  output: CyberMasterOutput,
                  direction: CyberMasterDirection) -> [UInt8]
{
    let linkType: UInt8 = 0x02                  // radio
    let cmdCode = 0x21 + output.rawValue
    let data: [UInt8] = [linkType, channel, cmdCode, direction.rawValue]
    return cyberMasterPacket(cmd: 0x41, data: data)
}

func playSoundPacket(channel: UInt8, soundNumber: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0x50, soundNumber]
    return cyberMasterPacket(cmd: 0x41, data: data)
}

func unlockCyberMasterFirmware(channel: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0xA5]  // 0xA5 = unlock command
    return cyberMasterPacket(cmd: 0x41, data: data)
}

func pbAlivePacket(channel: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0x20] // 0x20 = PBAlive
    return cyberMasterPacket(cmd: 0x41, data: data)
}

The above was mostly written by ChatGPT by feeding it the "Controlling LEGO® Programmable Bricks Technical Reference" PDF.

Will keep tinkering, and report back. Thanks team!

Posted

I've tried going back to a null modem cable and now using baud rate of 2400.

Alas, whilst the transmitter LED is going triggering with each command, I still get nothing on the receiver:
 

Port opened on channel 0
Received: {length = 1, bytes = 0x00}02 05 41 02 00 20 66 03PBAlive sent
Received: {length = 1, bytes = 0x00}02 05 41 02 00 A5 E3 03UnlockFirmware sent on channel 002 06 41 02 00 21 7F 1B 0302 06 41 02 00 21 81 E5 0302 06 41 02 00 22 7F 18 0302 06 41 02 00 22 81 E6 0302 06 41 02 00 23 7F 19 0302 06 41 02 00 23 81 E7 03
Port closed on channel 1
Port opened on channel 1
Received: {length = 1, bytes = 0x00}02 05 41 02 01 20 67 03PBAlive sent
Received: {length = 1, bytes = 0x00}02 05 41 02 01 A5 E2 03UnlockFirmware sent on channel 102 06 41 02 01 21 7F 1A 0302 06 41 02 01 21 81 E4 0302 06 41 02 01 22 7F 19 0302 06 41 02 01 22 81 E7 0302 06 41 02 01 23 7F 18 0302 06 41 02 01 23 81 E6 03
Port closed on channel 1
Port opened on channel 2
Received: {length = 1, bytes = 0x00}02 05 41 02 02 20 64 03PBAlive sent
Received: {length = 1, bytes = 0x00}02 05 41 02 02 A5 E1 03UnlockFirmware sent on channel 202 06 41 02 02 21 7F 19 0302 06 41 02 02 21 81 E7 0302 06 41 02 02 22 7F 1A 0302 06 41 02 02 22 81 E4 0302 06 41 02 02 23 7F 1B 0302 06 41 02 02 23 81 E5 03
Port closed on channel 2
Port opened on channel 3
Received: {length = 1, bytes = 0x00}02 05 41 02 03 20 65 03PBAlive sent
Received: {length = 1, bytes = 0x00}02 05 41 02 03 A5 E0 03UnlockFirmware sent on channel 302 06 41 02 03 21 7F 18 0302 06 41 02 03 21 81 E6 0302 06 41 02 03 22 7F 1B 0302 06 41 02 03 22 81 E5 0302 06 41 02 03 23 7F 1A 0302 06 41 02 03 23 81 E4 03
Port closed on channel 3

Will keep tinkering, as I'm HOPING it's just a bug in the Swift code rather than something wrong with the Lego itself.

Posted

Hi Chris,

I need to get back to my notes (yes, written notes by me in scratch books made of paper :pir-huzzah2:) - but this all seems to be reasonable/doable.

I am a bit busy right now - just go on trying, I'll throw in what I can during the next few days. Right now, I am installing highly reflecting stainless steel sheets (outside) on my attic windows - this has an incredible effect on temperature up there :D

Best
Thorsten

Posted

Note to self... maehw writes:

Quote

As mentioned there, a serial connection with the RF tower using 2400 baud, 8 data bits, odd parity, 1 stop bit worked. I am not sure about the command set. But the commands have a 4 byte header (FE 00 00 FF), one command byte (with it's one's complement) plus at least one data byte (with it's one's complement; maybe the number of data bytes depends on the command) and finally a checksum byte (and it's one's complement) - which is quite similar to the RCX IR protocol.

 

Posted

Note to self... I've tweaked the code, but still not getting any response on the receiver.

Port opened on channel 0
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}55 FF 00 02 FD 05 FA 41 BE 02 FD 00 FF 20 DF 66 99 03 FC D3 2C
→ PBAlive sent
→ 55 FF 00 02 FD 05 FA 41 BE 02 FD 00 FF A5 5A E3 1C 03 FC D5 2A
→ UnlockFirmware sent on channel 055 FF 00 02 FD 06 F9 41 BE 02 FD 00 FF 21 DE 7F 80 1B E4 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 00 FF 29 D6 7F 80 13 EC 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 00 FF 50 AF 00 FF 15 EA 03 FC B3 4C
Port closed on channel 0
Port opened on channel 1
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}55 FF 00 02 FD 05 FA 41 BE 02 FD 01 FE 20 DF 67 98 03 FC D5 2A
→ PBAlive sent
→ 55 FF 00 02 FD 05 FA 41 BE 02 FD 01 FE A5 5A E2 1D 03 FC D5 2A
→ UnlockFirmware sent on channel 155 FF 00 02 FD 06 F9 41 BE 02 FD 01 FE 29 D6 7F 80 12 ED 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 01 FE 22 DD 7F 80 19 E6 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 01 FE 50 AF 00 FF 14 EB 03 FC B3 4C
Port closed on channel 1
Port opened on channel 2
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}55 FF 00 02 FD 05 FA 41 BE 02 FD 02 FD 20 DF 64 9B 03 FC D3 2C
→ PBAlive sent
→ 55 FF 00 02 FD 05 FA 41 BE 02 FD 02 FD A5 5A E1 1E 03 FC D5 2A
→ UnlockFirmware sent on channel 255 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 21 DE 7F 80 19 E6 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 22 DD 7F 80 1A E5 03 FC 0B F455 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 23 DC 7F 80 1B E4 03 FC 0D F255 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 50 AF 00 FF 17 E8 03 FC B7 48
Port closed on channel 2
Port opened on channel 3
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}55 FF 00 02 FD 05 FA 41 BE 02 FD 03 FC 20 DF 65 9A 03 FC D5 2A
→ PBAlive sent
→ 55 FF 00 02 FD 05 FA 41 BE 02 FD 03 FC A5 5A E0 1F 03 FC D5 2A
→ UnlockFirmware sent on channel 355 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 21 DE 7F 80 18 E7 03 FC 09 F655 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 22 DD 7F 80 1B E4 03 FC 0D F255 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 23 DC 7F 80 1A E5 03 FC 0D F255 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 50 AF 00 FF 16 E9 03 FC B7 48
Port closed on channel 3

My current code is:

 

import Foundation
import ORSSerial

final class SerialManager: NSObject, ObservableObject, ORSSerialPortDelegate {

    @Published var availablePorts: [ORSSerialPort] = []
    @Published var selectedPort: ORSSerialPort?
    @Published var isOpen = false
    @Published var radioChannel: UInt8 = 0

    // For toggle-bit handling
    private var lastOutputOpcode: UInt8? = nil

    override init() {
        super.init()
        refreshPorts()
        ORSSerialPortManager.shared().addObserver(self, forKeyPath: "availablePorts", options: .new, context: nil)
    }

    deinit {
        ORSSerialPortManager.shared().removeObserver(self, forKeyPath: "availablePorts")
    }

    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey: Any]?,
        context: UnsafeMutableRawPointer?
    ) {
        if keyPath == "availablePorts" {
            refreshPorts()
        }
    }

    func refreshPorts() {
        availablePorts = ORSSerialPortManager.shared().availablePorts
    }
    
    func openPort() {

        // -------------------------------------------------------------------------------------------
        // SOURCE: https://www.eurobricks.com/forum/forums/topic/196691-cannot-donwload-code-to-cybermaster-unit/#findComment-3658973
        //
        // The IR/RF towers are as dumb as a rock. They don't know anything about flow control other
        // than having the bridge between RTS and CTS = "always ready". BricxCC/NQC don't even bother,
        // the LEGO software does though - the SCOUT tool for example claims there is no tower when
        // the corresponding pin is not pulled high. The electronics in the tower is naturally always
        // way faster than 9600 baud can ever be - it doesn't have to do anything other than emitting
        // the IR/RF serial signal coming in and vice versa.
        //
        // Not the point. But when you have xon/xoff activated, any "tower echo" or CM reply with
        // value 0x13 may stop the transmission, as this is the character to signal "device is busy".
        // For ASCII character transmission, all is fine, as these begin at 0x20 (space). All
        // characters below (0x00 - 0x1F = 32) are considered control codes. LEGO byte codes are
        // of binary nature - no control chars at all. That may be an issue when transmitting longer
        // sequences of bytes (a program). And then no further bytes are coming in, as the towers
        // don't do anything smart, as for example sending 0x11 = "ready" ... 
        // -------------------------------------------------------------------------------------------

        // -------------------------------------------------------------------------------------------
        // SOURCE: https://www.eurobricks.com/forum/forums/topic/208025-reverse-engineering-lego-technic-cybermaster-c2/#findComment-3784164
        //
        // The close to hardware protocol is 2400 baud, 8 data bits, odd parity. Null modem cable is fine.
        // The close to software protocol is "LEGO byte code", as used by LEGO software for the RCX,
        // SCOUT, Spybots, Cybermaster programmable bricks (PBricks), as well as by NQC/BricxCC.
        // -------------------------------------------------------------------------------------------

        guard let port = selectedPort else { return }
        port.baudRate = 2400
        port.numberOfDataBits = 8
        port.numberOfStopBits = 1
        port.parity = .odd
        port.usesRTSCTSFlowControl = false
        port.usesDTRDSRFlowControl = false
        port.dtr = true
        port.rts = true
        port.delegate = self
        port.open()

        port.rts = false
        port.dtr = false
        usleep(100000) // 100 ms
        port.rts = true
        port.dtr = true
        usleep(100000)
    }

    func closePort() {
        selectedPort?.close()
    }
    
    func send(_ data: Data) {
        guard isOpen else { return }
        let encoded = encodeForTower([UInt8](data))
        let bytesStr = encoded.map { String(format: "%02X", $0) }.joined(separator: " ")
        print("→ \(bytesStr)")
        selectedPort?.send(Data(encoded))
    }

    // MARK: - ORSSerialPortDelegate

    func serialPortWasOpened(_ serialPort: ORSSerialPort) {
        isOpen = true
        print("Port opened on channel \(self.radioChannel)")

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {

            self.send(Data(pbAlivePacket(channel: self.radioChannel)))
            print("→ PBAlive sent")

            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                let unlock = unlockCyberMasterFirmware(channel: self.radioChannel)
                self.send(Data(unlock))
                print("→ UnlockFirmware sent on channel \(self.radioChannel)")
            }
        }
    }

    func serialPortWasClosed(_ serialPort: ORSSerialPort) {
        isOpen = false
        print("Port closed on channel \(self.radioChannel)")
    }

    func serialPortWasRemovedFromSystem(_ serialPort: ORSSerialPort) {
        closePort()
        refreshPorts()
    }

    func serialPort(_ port: ORSSerialPort, didReceive data: Data) {
        print("Received: \(data as NSData)")
    }

    func serialPort(_ port: ORSSerialPort, didEncounterError error: Error) {
        print("Serial error:", error)
    }

    // MARK: - Toggle bit aware outputPacket for motors
    func outputPacket(channel: UInt8,
                      output: CyberMasterOutput,
                      direction: CyberMasterDirection) -> [UInt8]
    {
        let linkType: UInt8 = 0x02
        var cmdCode = 0x21 + output.rawValue

        // Toggle the 0x08 bit if sending the same opcode as last time (ignoring 0x08 itself)
        if let last = lastOutputOpcode, (last & 0xF7) == cmdCode {
            cmdCode ^= 0x08
        }
        lastOutputOpcode = cmdCode

        let data: [UInt8] = [linkType, channel, cmdCode, direction.rawValue]
        return cyberMasterPacket(cmd: 0x41, data: data)
    }
}

/// Tower-level encoding: preamble, byte complements, checksum
func encodeForTower(_ bytes: [UInt8]) -> [UInt8] {
    var encoded: [UInt8] = [0x55, 0xFF, 0x00]  // 3-byte preamble
    var sum: UInt16 = 0
    for b in bytes {
        encoded.append(b)
        encoded.append(0xFF &- b)
        sum = (sum + UInt16(b)) & 0xFF
    }
    // LEGO checksum: sum of data bytes mod 256, then its complement
    let checksum = UInt8(sum & 0xFF)
    encoded.append(checksum)
    encoded.append(0xFF &- checksum)
    return encoded
}

/// Build a CyberMaster packet (PBrick-level)
func cyberMasterPacket(cmd: UInt8, data: [UInt8]) -> [UInt8] {
    let stx: UInt8 = 0x02
    let etx: UInt8 = 0x03
    let len = UInt8(1 + data.count + 1)          // CMD + data + XOR
    var pkt  = [stx, len, cmd] + data
    let chk  = pkt[1...].reduce(0, ^)            // XOR LEN,CMD,DATA…
    pkt += [chk, etx]
    return pkt
}

enum CyberMasterOutput: UInt8 { case left=0, right, black }
enum CyberMasterDirection: UInt8 { case forward=0x7F, backward=0x81, off=0x00 }

func playSoundPacket(channel: UInt8, soundNumber: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0x50, soundNumber]
    return cyberMasterPacket(cmd: 0x41, data: data)
}

func unlockCyberMasterFirmware(channel: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0xA5]  // 0xA5 = unlock command
    return cyberMasterPacket(cmd: 0x41, data: data)
}

func pbAlivePacket(channel: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let data: [UInt8] = [linkType, channel, 0x20] // 0x20 = PBAlive
    return cyberMasterPacket(cmd: 0x41, data: data)
}

 

Posted

Note to self... I tried changing to:

func unlockCyberMasterFirmware(channel: UInt8) -> [UInt8] {
    let linkType: UInt8 = 0x02
    let unlockOpcode: UInt8 = 0xA5
    // The magic unlock string as per LEGO docs:
    let unlockString = Array("Do you byte, when I knock?".utf8)
    let data: [UInt8] = [linkType, channel, unlockOpcode] + unlockString
    return cyberMasterPacket(cmd: 0x41, data: data)
}

...but still nothing.

Posted

Hi Chris,

this is all a bit weird, but I also struggle a bit with your code, as the frames you are sending appear longer, as I would expect.

I'd send rather direct codes (e.g., beep or motor on - the default power setting of the motors is 7 after "booting up" the PBrick) - then you don't need to wait for replies and can check whether the unit receives RF frames and executes them correctly. There were similar issues discussed in one of the threads Carsten pointed you to; direct commands worked, programming not.

Do direct commands work in your case?

Best
Thorsten

Posted

Thanks for your reply Thorsten!

Quote

this is all a bit weird, but I also struggle a bit with your code, as the frames you are sending appear longer, as I would expect.

It's entirely possible all the messages I'm generating in Swift are totally wrong, haha.

It's also entirely possible I'm over complicating things - or mixing up CyberMaster code with other Lego product code.

Hopefully an easy question for you... For CyberMaster, do you actually need to do the "Do you byte, when I knock?" dance?

Quote

I'd send rather direct codes (e.g., beep or motor on - the default power setting of the motors is 7 after "booting up" the PBrick)

I was actually thinking that I WAS sending direct codes. Maybe I'm completely misunderstanding something.

For reference, attached is what the user interface currently looks like. I was EXPECTING that pressing the Forward button for the left wheel, for example, would be sending a direct command.

And no - so far I haven't been able to make the receiver do ANYTHING. If I could make it beep, that would be amazing.

According to ChatGPT, it seems to think the code is right - it's the power levels from the USB to serial adapter that are the issue, but given your comments, I think it's more likely that the messages I'm outputting via the serial port is nonsense.

I'll keep tinkering... but if you have any ideas or suggestions, let me know! In a perfect world, I'd love to know what bytes I need to send to just make it beep.

Thanks heaps!

Screenshot 2025-07-06 at 7.28.37 pm Medium.jpeg

Posted (edited)

Hello,

What Settings did you use for DTR (Pin 4) and RTS (Pin 7) of Sub-D connector at RF-Tower ?

See Schematic
There is needed +12V on DTR (Low in UART-Register) and -12V on RTS (High)
 

Jo

Edited by BrickTronic
Posted

Thanks for this information Jo!

To be honest, I'm not sure...

I've tried two seperate USB to serial adapters (photo attached):

USB-Serial Controller :

  Product ID:	0x23a3
  Vendor ID:	0x067b  (Prolific Technology, Inc.)
  Version:	6.05
  Serial Number:	CVDYf146B11
  Speed:	Up to 12 Mb/s
  Manufacturer:	Prolific Technology Inc. 
  Location ID:	0x00100000 / 1
  Current Available (mA):	500
  Current Required (mA):	100
  Extra Operating Current (mA):	0

USB HS Serial Converter:

  Product ID:	0x6001
  Vendor ID:	0x0403  (Future Technology Devices International Limited)
  Version:	4.00
  Serial Number:	FTC87U6C
  Speed:	Up to 12 Mb/s
  Manufacturer:	FTDI
  Location ID:	0x00120000 / 3
  Current Available (mA):	500
  Current Required (mA):	44
  Extra Operating Current (mA):	0

I'm using the following settings:

guard let port = selectedPort else { return }
port.baudRate = 2400
port.numberOfDataBits = 8
port.numberOfStopBits = 1
port.parity = .odd
port.usesRTSCTSFlowControl = false
port.usesDTRDSRFlowControl = false
port.dtr = true
port.rts = true
port.delegate = self
port.open()

I don't have a multimeter with me, so I haven't measured the voltage coming off the pins.

Given one of the adapters specifically says it's an RS-232 adapter though, I'm ASSUMING its standard voltages.

I assume USB to serial adapters work similar to old-school serial ports on PC's?

IMG_9479 Small.jpeg

Posted (edited)
1 hour ago, Chris Hocking said:

Thanks for this information Jo!

...

USB-Serial Controller :

  Product ID:	0x23a3
  Vendor ID:	0x067b  (Prolific Technology, Inc.)
  Version:	6.05
  Serial Number:	CVDYf146B11
  Speed:	Up to 12 Mb/s
  Manufacturer:	Prolific Technology Inc. 
  Location ID:	0x00100000 / 1
  Current Available (mA):	500
  Current Required (mA):	100
  Extra Operating Current (mA):	0

USB HS Serial Converter:

  Product ID:	0x6001
  Vendor ID:	0x0403  (Future Technology Devices International Limited)
  Version:	4.00
  Serial Number:	FTC87U6C
  Speed:	Up to 12 Mb/s
  Manufacturer:	FTDI
  Location ID:	0x00120000 / 3
  Current Available (mA):	500
  Current Required (mA):	44
  Extra Operating Current (mA):	0

FTDI usually are USB to TTL Converters that still need RS232 Level-Translater like an MAX232 compatible Chip
Does your Adatper have an 9-Pin Sub-D connector on the RS232 side or only single Wires for Bread-Board use ?

guard let port = selectedPort else { return }
port.baudRate = 2400
port.numberOfDataBits = 8
port.numberOfStopBits = 1
port.parity = .odd
port.usesRTSCTSFlowControl = false
port.usesDTRDSRFlowControl = false
port.dtr = true
port.rts = true
port.delegate = self
port.open()

Please try DTR Pin-4 Low (False)

Jo

 

Edited by BrickTronic
Posted (edited)
1 hour ago, BrickTronic said:

There is needed +12V on DTR

Ho Jo, Chris,

wow, nice find - I was searching for the schematics of the RF tower forever!

I am using 2 types of USB2Serial converters, both work. One is operating the lines with about +/-5V, the other with +/-9V and they both work fine with the RF tower. The RTS/CTS bridge (also present in the RCX IR tower) is briefly tested by LEGO software (for RCX and SCOUT) upon startup; if CTS is not mirroring an RTS pulse generated by the software, it says "No Tower". 

My own program for the IR tower just use RX/TX/GND, as the IR tower is totally dumb; >whatever< arrives on the tower RX line is cranked out as 38 kHz modulated IR light. The RF tower seems to behaving similarly, but I am not an electronics expert, not even an apprentice - you can read the schematics as if they were clear text Jo, right?

EDIT: The tower LED responds to input ("blinking") - doesn't that mean, data come through?

Best
Thorsten

Edited by Toastie
Posted
5 minutes ago, Toastie said:

Ho Jo, Chris,

wow, nice find - I was searching for the schematics of the RF tower forever!

I am using 2 types of USB2Serial converters, both work. One is operating the lines with about +/-5V, the other with +/-9V and they both work fine with the RF tower. The RTS/CTS bridge (also present in the RCX IR tower) is briefly tested by LEGO software (for RCX and SCOUT) upon startup; if CTS is not mirroring an RTS pulse generated by the software, it says "No Tower". 

My own program for the IR tower just use RX/TX/GND, as the IR tower is totally dumb; >whatever< arrives on the tower RX line is cranked out as 38 kHz modulated IR light. The RF tower seems to behaving similarly, but I am not an electronics expert, not even an apprentice - you can read the schematics as if they were clear text Jo, right?

Best
Thorsten

Hello,

I confirm. The (RCX) IR-Tower uses also RTS=High/True to have -12V (-3 to -12V) on Pin-7 of 9-Pin Sub-D connector to secure propper RS232 Level on TXD Pin 3 to your Computer
Does you remind the Schematic

Your Projects like your MulPi shows, that you are much more than an apprentice :-)

Jo

Posted

Hi Chris,

Interesting to see another person in Australia playing with these old things, saw this discussion and had to quit lurking on Eurobricks since 2015 and join in!

The other day I came across some interesting information by searching for the FCC ID of the Cybermaster unit. Searching on Google for FCC 71797 will get you some good stuff on the Cybermaster unit. (Which seems to have been called "Spirit" during development - is that where SPIRIT.OCX came from?) Likewise, taking the Bricklink element ID for the tower, 71846, and searching FCC 71846 brings up a page on fcc.io which has a schematic and a description of operation for the tower.

That shows the header as FE 00 00 FF for the Cybermaster, not the 55 FF 00 used for IR in the RCX and similar. It explains that the tower checks for the FE to ensure the baud rate is correct (2400 bps), and won't power up the radio circuitry unless it gets the FE.

I'm using an FT232 USB to serial converter cable on an old Windows 7 machine. BricxCC was able to sometimes connect with the default settings. I needed to set the Receive and Transmit buffer sizes to the lowest value (64) and the Latency Timer to the lowest setting of 1 ms to get BricxCC to reliably communicate.

What are the motors on your unit like? Mine had one with a dislodged magnet that needed to be pushed back in with a vice, and one with a disintegrating magnet that I replaced with one from a working 71427 motor. It's happily running around the floor now and avoiding obstacles.

Posted (edited)
1 hour ago, HughC said:

That shows the header as FE 00 00 FF for the Cybermaster, not the 55 FF 00 used for IR in the RCX and similar. It explains that the tower checks for the FE to ensure the baud rate is correct (2400 bps), and won't power up the radio circuitry unless it gets the FE.

Wow, that is really nice information! Thanks a lot!

First, in the table in this document: https://fccid.io/NPI71846/Operational-Description/12-23748 section 1.1, the header is described as being FF 00 00 FF, whereas in the text the first header byte is described as FE. Hmmm ...

Second, I don't understand how the tower checks for the correct Baud rate other than sensing a certain time delay, if at all? In the table, it says for the first header byte "TX oscillator starts up" and "PIC synchs + receiver enables". I guess, these two always start up when something goes high (= start bit, RS232 side) and then some timing checks for some H or L period? FE is 254 = H startbit + HLLL LLLL + odd parity and L stop bit (on the RS232 level side); there would not be much of a difference timing-wise when receiving "FF" as H startbit + LLLL LLLL + odd parity and L stop bit, would it? Also, two 00 are following, which seem to be just for "stabilizing" everything. With the next FF = fourth header byte, everything should be synched, and "synched bit banging" may start ...

On the IR tower, 55 FF 00 was used to “burn in” the IR LEDs after being off for some time; these bytes are not checked in the tower nor on the RCX, as far as I remember, as the 55 maybe crippled ... the FF and 00 gave rather stable signals and then synching was also pretty much safely done.

Very interesting! When Chris has made a connection to his CM unit, he can clarify the FE/FF confusion!

EDIT: In section 1.5 in the above referenced document, it says D2 (green LED) indicates when data are transmitted. So, I guess, at least the RF circuitry is fired-up in Chris' experiments? 

All the best
Thorsten   

       

Edited by Toastie
Posted

Amazing - thanks for all your ideas and comments Toastie, HughC and BrickTronic!

I did feed BrickTronic's schematic into ChatGPT and it told me that:

Quote

What the Schematic Confirms

1. RS232 Signal Levels Are Required

  • The tower uses an ICL3232 (U2), which is a classic RS232 line driver/receiver.

    • This IC converts the true RS232 voltage swing (+/- 10-12V) from the PC serial port to TTL for the logic/RF section.

    • This means the tower expects “real” RS232 on its DB9 port, NOT TTL-level serial.

  • If you use a USB-to-serial adapter that only provides 0-5V or 0-3.3V logic signals (TTL), the tower may not work at all or may only partially work (just enough to blink the LED).

2. Pinout

  • Standard DB9 serial, with null modem cable needed (TX and RX crossed, GND straight).

  • Pin 5: GND, Pin 3: TXD, Pin 2: RXD.

  • No flow control (RTS/CTS inside tower are looped together).

3. LED

  • The green LED is connected to logic that will light on RX activitynot on RF transmission confirmation.

4. Transmitter Section

  • RF modulator and antenna circuit are separate, controlled by data from the serial logic.

  • If the input voltage swings are too low (as with TTL), the ICL3232 may not reliably transmit the logic to the RF section.

So whilst I can confirm that my code is definitely sending "stuff" to the transmitter, it doesn't necessarily mean that data is being transmitted.

HughC - I haven't been able to actually get the motors working at all yet - so I have no idea if they still work or not, haha.

I updated my code to:

/// Tower-level encoding: preamble, byte complements, checksum
func encodeForTower(_ bytes: [UInt8]) -> [UInt8] {
    //var encoded: [UInt8] = [0x55, 0xFF, 0x00]  // 3-byte preamble for RCX/Scout IR
    var encoded: [UInt8] = [0xFE, 0x00, 0x00, 0xFF] // Cybermaster RF
    var sum: UInt16 = 0
    for b in bytes {
        encoded.append(b)
        encoded.append(0xFF &- b)
        sum = (sum + UInt16(b)) & 0xFF
    }
    // LEGO checksum: sum of data bytes mod 256, then its complement
    let checksum = UInt8(sum & 0xFF)
    encoded.append(checksum)
    encoded.append(0xFF &- checksum)
    return encoded
}

However, it still doesn't work:

Port opened on channel 0
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}
→ FE 00 00 FF 02 FD 05 FA 41 BE 02 FD 00 FF 20 DF 66 99 03 FC D3 2C
→ PBAlive sent
→ FE 00 00 FF 02 FD 1F E0 41 BE 02 FD 00 FF A5 5A 44 BB 6F 90 20 DF 79 86 6F 90 75 8A 20 DF 62 9D 79 86 74 8B 65 9A 2C D3 20 DF 77 88 68 97 65 9A 6E 91 20 DF 49 B6 20 DF 6B 94 6E 91 6F 90 63 9C 6B 94 3F C0 B7 48 03 FC A3 5C
→ UnlockFirmware sent on channel 0
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 00 FF 50 AF 00 FF 15 EA 03 FC B3 4C
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 00 FF 50 AF 00 FF 15 EA 03 FC B3 4C
Port closed on channel 0
Port opened on channel 1
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}
→ FE 00 00 FF 02 FD 05 FA 41 BE 02 FD 01 FE 20 DF 67 98 03 FC D5 2A
→ PBAlive sent
→ FE 00 00 FF 02 FD 1F E0 41 BE 02 FD 01 FE A5 5A 44 BB 6F 90 20 DF 79 86 6F 90 75 8A 20 DF 62 9D 79 86 74 8B 65 9A 2C D3 20 DF 77 88 68 97 65 9A 6E 91 20 DF 49 B6 20 DF 6B 94 6E 91 6F 90 63 9C 6B 94 3F C0 B6 49 03 FC A3 5C
→ UnlockFirmware sent on channel 1
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 21 DE 7F 80 1A E5 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 29 D6 81 7E EC 13 03 FC E5 1A
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 22 DD 7F 80 19 E6 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 2A D5 81 7E EF 10 03 FC E9 16
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 23 DC 7F 80 18 E7 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 2B D4 81 7E EE 11 03 FC E9 16
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 01 FE 50 AF 00 FF 14 EB 03 FC B3 4C
Port closed on channel 1
Port opened on channel 2
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}
→ FE 00 00 FF 02 FD 05 FA 41 BE 02 FD 02 FD 20 DF 64 9B 03 FC D3 2C
→ PBAlive sent
→ FE 00 00 FF 02 FD 1F E0 41 BE 02 FD 02 FD A5 5A 44 BB 6F 90 20 DF 79 86 6F 90 75 8A 20 DF 62 9D 79 86 74 8B 65 9A 2C D3 20 DF 77 88 68 97 65 9A 6E 91 20 DF 49 B6 20 DF 6B 94 6E 91 6F 90 63 9C 6B 94 3F C0 B5 4A 03 FC A3 5C
→ UnlockFirmware sent on channel 2
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 02 FD 21 DE 7F 80 19 E6 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 02 FD 29 D6 7F 80 11 EE 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 02 FD 50 AF 00 FF 17 E8 03 FC B7 48
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 02 FD 22 DD 7F 80 1A E5 03 FC 0B F4
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 02 FD 23 DC 7F 80 1B E4 03 FC 0D F2
Port closed on channel 2
Port opened on channel 3
Received: {length = 1, bytes = 0x00}
Received: {length = 1, bytes = 0x00}
→ FE 00 00 FF 02 FD 05 FA 41 BE 02 FD 03 FC 20 DF 65 9A 03 FC D5 2A
→ PBAlive sent
→ FE 00 00 FF 02 FD 1F E0 41 BE 02 FD 03 FC A5 5A 44 BB 6F 90 20 DF 79 86 6F 90 75 8A 20 DF 62 9D 79 86 74 8B 65 9A 2C D3 20 DF 77 88 68 97 65 9A 6E 91 20 DF 49 B6 20 DF 6B 94 6E 91 6F 90 63 9C 6B 94 3F C0 B4 4B 03 FC A3 5C
→ UnlockFirmware sent on channel 3
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 03 FC 21 DE 7F 80 18 E7 03 FC 09 F6
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 03 FC 23 DC 7F 80 1A E5 03 FC 0D F2
→ FE 00 00 FF 02 FD 06 F9 41 BE 02 FD 03 FC 50 AF 00 FF 16 E9 03 FC B7 48
Port closed on channel 3

I'll keep tinkering...

My USB to RS232 adapter looks like this:

IMG_9482 Small.jpeg

Posted

I tried BricxCC test_release20120724 on a Windows PC using the same USB to RS232 and I just get "Cannot find brick. Switch it on or move it closer and press OK".

However, I CAN see the status light on the receiver flashing away, so some communication is actually happening - which is something I haven't been able to make it do on my Mac using Swift.

So baby steps... but still not working.

Posted (edited)

Hi Chris,

what version of windows? On what COM port are you running the USB2Ser adapter?

EDIT: I am asking about the COM port used, because I ran into the same issue ("can't find ...") although brick and tower were both there and on and working, when having the adapter on a COM port > COM8. Now this could be my outdated version of BricxCC - I'll have to check.

On the other hand, the flashing on the PBrick is indeed encouraging. However, if you can't get it to work with BricxCC then it may become really difficult ...

Any terminal program should also so the trick; I am using HTerm for that purpose, but others just laughed at me (boomer here) when mentioning that.

Later today, I shall break out my CM PBricks and see whether I can get it to work again.

Best
Thorsten

Edited by Toastie
Posted

I believe the PC is running Windows 11 Home (24H2).

I tried using COM3 and COM4 (one of my USB to RS232 adapters has two ports). I tried adjusting the settings as per HughC's suggestions too.

There was communication happening - both the transmitter and receiver were flashing away - which is something I've never seen before on my Mac.

Maybe I just need to find another USB to RS232 adapter that definitely outputs RS232 levels?

Posted

It might be worth trying another USB to RS232 adapter, they are all a bit different! From playing with old bus destination controllers, the issue is not always the voltage, but also how the adapter goes about sending data. Some will queue up a few bytes to send on the PC side, then send in one USB transfer - that can cause odd delays that upset some devices. Then there's the way they receive, and again if they wait to have a few bytes before transferring things up the USB cable.

A bit more playing with my Windows XP laptop, FT232 cable and Cybermaster tonight. I used Portmon to record as BricxCC opened the port and sent two notes to the Cybermaster to play - hopefully this inserted properly:

2	0.03646972	BricxCC.exe	IRP_MJ_CREATE	VCP0	SUCCESS	Options: Open 	
3	0.00000447	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
4	0.00000307	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
5	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
6	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
7	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
8	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
9	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
10	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
11	0.00176670	BricxCC.exe	IOCTL_SERIAL_SET_BAUD_RATE	VCP0	SUCCESS	Rate: 2400	
12	0.00198237	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
13	0.00197399	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
14	0.00198377	BricxCC.exe	IOCTL_SERIAL_SET_LINE_CONTROL	VCP0	SUCCESS	StopBits: 1 Parity: NONE WordLength: 8	
15	0.00000307	BricxCC.exe	IOCTL_SERIAL_SET_CHAR	VCP0	SUCCESS	EOF:0 ERR:0 BRK:0 EVT:0 XON:1 XOFF:2	
16	0.00193907	BricxCC.exe	IOCTL_SERIAL_SET_HANDFLOW	VCP0	SUCCESS	Shake:1 Replace:0 XonLimit:100 XoffLimit:100	
17	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
18	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
19	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
20	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
21	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
22	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
23	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
24	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
25	0.00180917	BricxCC.exe	IOCTL_SERIAL_SET_BAUD_RATE	VCP0	SUCCESS	Rate: 2400	
26	0.00197539	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
27	0.00197120	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
28	0.00197288	BricxCC.exe	IOCTL_SERIAL_SET_LINE_CONTROL	VCP0	SUCCESS	StopBits: 1 Parity: ODD WordLength: 8	
29	0.00000279	BricxCC.exe	IOCTL_SERIAL_SET_CHAR	VCP0	SUCCESS	EOF:0 ERR:0 BRK:0 EVT:0 XON:1 XOFF:2	
30	0.00196282	BricxCC.exe	IOCTL_SERIAL_SET_HANDFLOW	VCP0	SUCCESS	Shake:1 Replace:0 XonLimit:100 XoffLimit:100	
31	0.00197483	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
32	0.00199020	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
33	0.00000559	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
34	0.00000670	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
35	0.00098923	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 8: FE 00 00 FF 10 EF 10 EF 	
36	0.00000391	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
37	0.00000307	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
38	0.40016566	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF EF 10 EF 10 	
39	0.00000615	BricxCC.exe	IRP_MJ_CLEANUP	VCP0	SUCCESS		
40	0.10638335	BricxCC.exe	IRP_MJ_CLOSE	VCP0	SUCCESS		
41	0.03720277	BricxCC.exe	IRP_MJ_CREATE	VCP0	SUCCESS	Options: Open 	
42	0.00000475	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
43	0.00000307	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
44	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
45	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
46	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
47	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
48	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
49	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
50	0.00179492	BricxCC.exe	IOCTL_SERIAL_SET_BAUD_RATE	VCP0	SUCCESS	Rate: 2400	
51	0.00197539	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
52	0.00197539	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
53	0.00195891	BricxCC.exe	IOCTL_SERIAL_SET_LINE_CONTROL	VCP0	SUCCESS	StopBits: 1 Parity: NONE WordLength: 8	
54	0.00000307	BricxCC.exe	IOCTL_SERIAL_SET_CHAR	VCP0	SUCCESS	EOF:0 ERR:0 BRK:0 EVT:0 XON:1 XOFF:2	
55	0.00196142	BricxCC.exe	IOCTL_SERIAL_SET_HANDFLOW	VCP0	SUCCESS	Shake:1 Replace:0 XonLimit:100 XoffLimit:100	
56	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
57	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
58	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
59	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
60	0.00000279	BricxCC.exe	IOCTL_SERIAL_GET_BAUD_RATE	VCP0	SUCCESS		
61	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_LINE_CONTROL	VCP0	SUCCESS		
62	0.00000223	BricxCC.exe	IOCTL_SERIAL_GET_CHARS	VCP0	SUCCESS		
63	0.00000251	BricxCC.exe	IOCTL_SERIAL_GET_HANDFLOW	VCP0	SUCCESS		
64	0.00181308	BricxCC.exe	IOCTL_SERIAL_SET_BAUD_RATE	VCP0	SUCCESS	Rate: 2400	
65	0.00197846	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
66	0.00199104	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
67	0.00197707	BricxCC.exe	IOCTL_SERIAL_SET_LINE_CONTROL	VCP0	SUCCESS	StopBits: 1 Parity: ODD WordLength: 8	
68	0.00000279	BricxCC.exe	IOCTL_SERIAL_SET_CHAR	VCP0	SUCCESS	EOF:0 ERR:0 BRK:0 EVT:0 XON:1 XOFF:2	
69	0.00195863	BricxCC.exe	IOCTL_SERIAL_SET_HANDFLOW	VCP0	SUCCESS	Shake:1 Replace:0 XonLimit:100 XoffLimit:100	
70	0.00196869	BricxCC.exe	IOCTL_SERIAL_SET_DTR	VCP0	SUCCESS		
71	0.00196338	BricxCC.exe	IOCTL_SERIAL_CLR_RTS	VCP0	SUCCESS		
72	0.00000335	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
73	0.00000559	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
74	0.00092889	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 8: FE 00 00 FF 18 E7 18 E7 	
75	0.00000307	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
76	0.00000279	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
77	0.39955637	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF E7 18 E7 18 	
78	0.00000503	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
79	0.00000531	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
80	0.00025841	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 60: FE 00 00 FF A5 5A 44 BB 6F 90 20 DF 79 86 6F 90 75 8A 20 DF 62 	
81	0.00000335	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
82	0.00000251	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
83	0.39992904	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 22: FF 5A A5 4A B5 75 8A 73 8C 74 8B 20 DF 61 9E 20 DF 62 9D 69 96 	
84	0.00000531	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:200 WM:0 WC:0	
85	0.20010085	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 33: 8B 20 DF 6F 90 66 99 66 99 20 DF 74 8B 68 97 65 9A 20 DF 62 9D 	
86	0.00000559	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
87	0.00000559	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
88	0.00060538	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 8: FE 00 00 FF 10 EF 10 EF 	
89	0.00000307	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
90	0.00000279	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
91	0.39954715	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF EF 10 EF 10 	
92	0.00000503	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
93	0.00000559	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
94	0.00089592	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 8: FE 00 00 FF 18 E7 18 E7 	
95	0.00000475	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
96	0.00000363	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
97	0.39987987	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF E7 18 E7 18 	
98	0.00000559	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
99	0.00000587	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
100	0.00080541	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 8: FE 00 00 FF 10 EF 10 EF 	
101	0.00000335	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
102	0.00000335	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
103	0.40025506	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF EF 10 EF 10 	
104	0.00000587	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
105	0.00000615	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
106	0.00104008	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 14: FE 00 00 FF 23 DC 88 77 01 FE 28 D7 D4 2B 	
107	0.00000307	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
108	0.00000307	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
109	0.39988043	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF DC 23 DC 23 	
110	0.00000587	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:-1 RM:0 RC:0 WM:0 WC:0	
111	0.00000643	BricxCC.exe	IRP_MJ_READ	VCP0	SUCCESS	Length 0: 	
112	0.00012851	BricxCC.exe	IRP_MJ_WRITE	VCP0	SUCCESS	Length 14: FE 00 00 FF 2B D4 B8 47 01 FE 28 D7 0C F3 	
113	0.00000363	BricxCC.exe	IRP_MJ_FLUSH_BUFFERS	VCP0	SUCCESS		
114	0.00000335	BricxCC.exe	IOCTL_SERIAL_SET_TIMEOUTS	VCP0	SUCCESS	RI:0 RM:0 RC:400 WM:0 WC:0	
115	0.39975081	BricxCC.exe	IRP_MJ_READ	VCP0	TIMEOUT	Length 5: FF D4 2B D4 2B 	

I also downloaded talkrcx from here and had a play: https://web.archive.org/web/20010415171811/http://www.phesk.demon.co.uk/lego/talkqbas.htm. It took a bit to hack it to run with FreeBASIC and send the Cybermaster header, but it did get some noises out of the Cybermaster.

Sending the sound opcodes from the RCX2 LASM byte codes in the RCX2 SDK worked well. Opcode 51/59 is the PlaySystemSound instruction and takes a parameter between 0 and 5, corresponding to RCX tones 1 to 6. The Cybermaster has the same tones.

Sending FE 00 00 FF 59 A6 05 FA 5E A1 got sound 6 from the Cybermaster.

Playing a certain tone also worked using PlayTone, which is 23/2B followed by the low byte for frequency, the high byte for frequency, and a byte for duration. An example: FE 00 00 FF 23 DC 88 77 01 FE 28 D7 D4 2B

A couple of thoughts on your code. One is that the RCX and seemingly the Cybermaster needs the the 0x08 bit of the command to toggle between instructions - it won't follow two instructions in a row that have the same value in the bit representing 8. So sending 23 then 51 would not work, but sending 23 then 59 would. After 59, the next instruction could be either 51 or 23, followed by 59 or 2B. Hopefully not a tricky change to make. Also, from memory, UnlockFirmware is used at the end of the firmware download on an RCX to boot the firmware - not sure if the Cybermaster has that one? Sound commands are always my favourite for testing because they are generally not too complicated, and you can tell quickly if it worked.

Sometimes BricxCC won't connect properly for me either, turning the Cybermaster off and on again helps eventually.

All the best with finding a well behaved USB to serial cable! Always a challenge getting these things to talk to modern hardware, but cracking that is part of the fun.

Posted
49 minutes ago, Chris Hocking said:

There was communication happening - both the transmitter and receiver were flashing away - which is something I've never seen before on my Mac.

Hi Chris,

CM PBrick and RF Tower back on the desk. Win11 64bit running BricxCC Ver. 3.3. build 3.3.8.9 (March 15, 2011), USB2Ser adapter on COM1.
Original LEGO seral cable (= 9 wire null modem cable, just checked again, serial always needs close attention ;) #71793, wiring is:
1 nc.; 2-> 3; 3->2; 4->4; 5->5; 6 nc; 7->8; 8->7; 9 nc.
This is a plain vanilla bare bone D-sub 9 null modem cable with RX and TX, CTS and RTS crossed, GND and DTR straight through, 1/6/9 not connected. This is not a full hardware handshake mull modem cable, where DTR (4) is wired to DSR (6) and CD (1)!

With BricxCC running, I made the following observations:

  1. Select "Port = COM1", "Brick Type = Cybermaster", and "OK" leads to blinking on both sides and connection is readily established. All controls work.
  2. Same as above, but with a full hardware handshake null modem cable. Works as well.
  3. Same as above, but replaced the LEGO (null) modem cable with my own, here just RX/TX (2/3) and GND (5) are connected:
    Both, tower and PBrick blink upon connect request, but message "Can't find brick" shows up.

This leads me to the suggestion that your USB2Ser adapter may be the culprit? 

As long as you have no connection with BricxCC, I guess programming your own code will be fairly difficult.

Best
Thorsten

11 minutes ago, HughC said:

It might be worth trying another USB to RS232 adapter, they are all a bit different!

Heehee - yes, I guess this is good advice! See above ;) your message came in when I pressed “submit reply” :pir-huzzah2:

I also just used HTerm to send "FE 00 00 FF 59 A6 05 FA 5E A1" to get a sound - works nicely and yes only once as on the RCX and other PBricks, then you have to "toggle". Messages (msg or msgz) go through without doing that, at least on the RCX.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...