Chris Hocking Posted July 3 Posted July 3 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! Quote
JopieK Posted July 5 Posted July 5 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. Quote
Toastie Posted July 5 Posted July 5 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): 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. 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 Quote
Chris Hocking Posted July 5 Author Posted July 5 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! Quote
Chris Hocking Posted July 5 Author Posted July 5 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 03 → PBAlive sent Received: {length = 1, bytes = 0x00} → 02 05 41 02 00 A5 E3 03 → UnlockFirmware sent on channel 0 → 02 06 41 02 00 21 7F 1B 03 → 02 06 41 02 00 21 81 E5 03 → 02 06 41 02 00 22 7F 18 03 → 02 06 41 02 00 22 81 E6 03 → 02 06 41 02 00 23 7F 19 03 → 02 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 03 → PBAlive sent Received: {length = 1, bytes = 0x00} → 02 05 41 02 01 A5 E2 03 → UnlockFirmware sent on channel 1 → 02 06 41 02 01 21 7F 1A 03 → 02 06 41 02 01 21 81 E4 03 → 02 06 41 02 01 22 7F 19 03 → 02 06 41 02 01 22 81 E7 03 → 02 06 41 02 01 23 7F 18 03 → 02 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 03 → PBAlive sent Received: {length = 1, bytes = 0x00} → 02 05 41 02 02 A5 E1 03 → UnlockFirmware sent on channel 2 → 02 06 41 02 02 21 7F 19 03 → 02 06 41 02 02 21 81 E7 03 → 02 06 41 02 02 22 7F 1A 03 → 02 06 41 02 02 22 81 E4 03 → 02 06 41 02 02 23 7F 1B 03 → 02 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 03 → PBAlive sent Received: {length = 1, bytes = 0x00} → 02 05 41 02 03 A5 E0 03 → UnlockFirmware sent on channel 3 → 02 06 41 02 03 21 7F 18 03 → 02 06 41 02 03 21 81 E6 03 → 02 06 41 02 03 22 7F 1B 03 → 02 06 41 02 03 22 81 E5 03 → 02 06 41 02 03 23 7F 1A 03 → 02 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. Quote
Toastie Posted July 5 Posted July 5 Hi Chris, I need to get back to my notes (yes, written notes by me in scratch books made of paper ) - 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 Quote
Chris Hocking Posted July 5 Author Posted July 5 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. Quote
Chris Hocking Posted July 5 Author Posted July 5 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 0 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 00 FF 21 DE 7F 80 1B E4 03 FC 09 F6 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 00 FF 29 D6 7F 80 13 EC 03 FC 09 F6 → 55 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 1 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 01 FE 29 D6 7F 80 12 ED 03 FC 09 F6 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 01 FE 22 DD 7F 80 19 E6 03 FC 09 F6 → 55 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 2 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 21 DE 7F 80 19 E6 03 FC 09 F6 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 22 DD 7F 80 1A E5 03 FC 0B F4 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 02 FD 23 DC 7F 80 1B E4 03 FC 0D F2 → 55 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 3 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 21 DE 7F 80 18 E7 03 FC 09 F6 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 22 DD 7F 80 1B E4 03 FC 0D F2 → 55 FF 00 02 FD 06 F9 41 BE 02 FD 03 FC 23 DC 7F 80 1A E5 03 FC 0D F2 → 55 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) } Quote
Chris Hocking Posted July 5 Author Posted July 5 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. Quote
Toastie Posted July 6 Posted July 6 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 Quote
Chris Hocking Posted July 6 Author Posted July 6 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! Quote
BrickTronic Posted July 6 Posted July 6 (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 July 6 by BrickTronic Quote
Chris Hocking Posted July 6 Author Posted July 6 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? Quote
BrickTronic Posted July 6 Posted July 6 (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 July 6 by BrickTronic Quote
Toastie Posted July 6 Posted July 6 (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 July 6 by Toastie Quote
BrickTronic Posted July 6 Posted July 6 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 Quote
HughC Posted July 6 Posted July 6 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. Quote
Toastie Posted July 6 Posted July 6 (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 July 6 by Toastie Quote
Chris Hocking Posted July 6 Author Posted July 6 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 activity—not 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: Quote
Chris Hocking Posted July 7 Author Posted July 7 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. Quote
Toastie Posted July 7 Posted July 7 (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 July 7 by Toastie Quote
Chris Hocking Posted July 7 Author Posted July 7 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? Quote
HughC Posted July 7 Posted July 7 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. Quote
Toastie Posted July 7 Posted July 7 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: Select "Port = COM1", "Brick Type = Cybermaster", and "OK" leads to blinking on both sides and connection is readily established. All controls work. Same as above, but with a full hardware handshake null modem cable. Works as well. 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” 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. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.