Toastie Posted January 20, 2025 Posted January 20, 2025 5 hours ago, Bliss said: As for your error msg, can you tell me what firmware you are using? is it an RCX 1.0? Just to recall: All RCX PBricks (hardware) run fine and behave exactly with the same firmware. The RCX 1.0 had the (wonderful) power jack, TLG saved some money be removing that power circuit in version 1.5. The 2.0 RCX is just a 1.5 RCX with newer firmware ^^. So the best RCX ever is the 1.0 Best, Thorsten Quote
Gunners TekZone Posted January 20, 2025 Posted January 20, 2025 (edited) OK... looks like it might be a python version thing... I had a "Doh!" moment and realised I have more serial IR towers, so can quickly swap the script and RCX between PC's for testing. Tested on Win10(64) with Python 3.12.8 and it recognised the button press. from legorcx import RCX import time rcx=RCX("COM2") # use the com port for you IR Tower. rcx.snd(1) # should play BEEP BEEP rcx.sensor(1).type(rcx.TypeTouch) # configue input 1 as a touch sensor rcx.mot(rcx.A).pow(7) # Set power to max rcx.mot(rcx.A).on() # run lamp on output A print("Dimming... Press button to step") for x in reversed(range(8)): print(x) rcx.mot(rcx.A).pow(x) while not rcx.getval(rcx.SrcSb,0): pass print("A = OFF") rcx.mot(rcx.A).off() time.sleep(.1) # needed to give prior command time to process before next command rcx.close() Dimming... Press button to step 7 6 5 4 3 2 1 0 A = OFF Shutting down. Edited January 20, 2025 by Gunners TekZone Quote
Bliss Posted January 20, 2025 Author Posted January 20, 2025 (edited) @Gunners TekZone, Could you please try the new version I just put in the dropbox? I modified the getval method with a little more proofing and it's not dependant of a fixed delay for the reply reading. Also added some timeout if it does not find the correct reply and will return "None" if it does not find a match. (Meaning that you could check the value return == None to make some actions) I modified the version numbering. I adjusted it to 2025.01.20 and fits with the acutal day for now but the last number is really an incrementing number. So if I put another updated file today, this number will be 21... Let me know how it goes. Thank you! 44 minutes ago, Gunners TekZone said: OK... looks like it might be a python version thing... I had a "Doh!" moment and realised I have more serial IR towers, so can quickly swap the script and RCX between PC's for testing. Tested on Win10(64) with Python 3.12.8 and it recognised the button press. I guess that means that I used some python functions that are not anymore compatible with the python version that works on Win7... I'll try to find which functions... I'm using the Thonny's default python version 3.10.11 to achieve my tests... Edited January 20, 2025 by Bliss Quote
Bliss Posted January 20, 2025 Author Posted January 20, 2025 @Gunners TekZone I updated again to version 2025.01.21. You may try it again in win 7 who knows... Quote
Gunners TekZone Posted January 20, 2025 Posted January 20, 2025 (edited) 11 minutes ago, Bliss said: You may try it again in win 7 who knows... Nice! That worked on my original script right away And, yes you are correct... No need to the pauses in the switch routine. Now more responsive in the stepping. Edited January 20, 2025 by Gunners TekZone Quote
Bliss Posted January 21, 2025 Author Posted January 21, 2025 I updated again cause I added the following commands: rcx.pwroff() # Powers off the brick rcx.sensor(rcx.inp3).clear() # clear the counter associated with the sensor. A rotation sensor for exemple. Quote
Gunners TekZone Posted January 21, 2025 Posted January 21, 2025 6 hours ago, Bliss said: So if I put another updated file today, this number will be 21... How about 2025.01.20.x With x reverting to 0 on next day? Reason I say, is that I already used the file creation data to try and determine if I am running latest version or not. Might as well keep the internal script version labeling the actual date of update (else confuse the snot out of people like me... "Whhhaa?... Did I sleep through the last few days or something?" Quote
Gunners TekZone Posted January 21, 2025 Posted January 21, 2025 (edited) 21 hours ago, Toastie said: With regard to PBricks (of all kinds), I like them to be "autonomous" in their own micro-environment I don't think this is the intent of Bliss's process... But it would be nice! That said, from a little Googling, running Python or even MicroPython onboard might not be a possible, or feasible, option on these little ol' yeller bricks Too slow and not enough memory. But as there are already many onboard OS options (Too many... I gets confused, thus never managed to use any of them), I would be happy with data/control/interaction sharing between an onboard OS of some flavor, and a PC running Python, handling communication with other newer devices running PyBricks. Edited January 21, 2025 by Gunners TekZone Quote
Bliss Posted January 21, 2025 Author Posted January 21, 2025 (edited) I updated the legorcx.py. (version 2025.01.21.0) Added "alive" command (rcx.alive()) which returns True if RCX detected, False otherwise. But I also rewrote the Read / Write engine. It was originally taken from lego interface B python module that is using multithreading. This is not needed for RCX as it is a Send command, read reply sequence. Commands/Replies must execute one after the other as I can see. So I had to syncronize between threads and I concluded that multithreading was not relevant for remote comm. with this brick. The code is simplified so might be more efficient... Let me know how this version works for you... Thank you! Bliss Edited January 21, 2025 by Bliss Quote
Gunners TekZone Posted January 21, 2025 Posted January 21, 2025 5 hours ago, Bliss said: Added "alive" command (rcx.alive()) which returns True if RCX detected, False otherwise. Test file seems to work as indicated On both my OS / Python versions. Quote
Bliss Posted January 27, 2025 Author Posted January 27, 2025 I just created a new topic about Lego Interface B and ESP32. I thought it would be better in a new thread. Quote
AJB2K3 Posted Monday at 07:03 PM Posted Monday at 07:03 PM Just started using the python module and its so easy to use, I just wish I could brain how its working in the background and what bytes its actually sending and receiving. Quote
Bliss Posted yesterday at 03:35 AM Author Posted yesterday at 03:35 AM Hello @AJB2K3, I'm glad you managed to do something with the python module LegoB.py. This is my prefered way to make programs in a modern PC that communicate with Interface B. I used the dacta driver from Steven Shamlian and adapted it to the latest version of Python. His web page also has links (some still working) to old reverse engineered information about the byte protocol of interface B. https://www.shamlian.net/projects/dacta/ However, I think I prefer more to use an ESP32 microcontroller with micropython. It makes the Interface B an almost standalone solution. And with the wifi capability of ESP32 and the MQTT client, it makes the Interface B able to join IoT platforms... Quote
Toastie Posted yesterday at 12:07 PM Posted yesterday at 12:07 PM 8 hours ago, Bliss said: His web page also has links (some still working) to old reverse engineered information about the byte protocol of interface B. https://www.shamlian.net/projects/dacta/ @AJB2K3 This is the place! I think maybe also this link provides some structured info about the Interface B protocol - it was put together some time ago with the help of many people her on EB: There is more further down as well, a bit on A/D conversion and so on. Best Thorsten Quote
AJB2K3 Posted 18 hours ago Posted 18 hours ago 6 hours ago, Toastie said: @AJB2K3 This is the place! I think maybe also this link provides some structured info about the Interface B protocol - it was put together some time ago with the help of many people her on EB: There is more further down as well, a bit on A/D conversion and so on. Best Thorsten I already have the structure and flow control for the Interface B but the RCX is a different beast. Quote
AJB2K3 Posted 17 hours ago Posted 17 hours ago Please bear with me as I am not braining very well. I've tried to send ser.write(b'\x55\xff\x00\x51\x01') after configuring the port in an attempt to make the RCX bleep but I'm obviously missing something here. I have tried reading through alligators source, the LASM document and @Bliss code but still turning dumb on this. Can I get some help please? Quote
Toastie Posted 16 hours ago Posted 16 hours ago 27 minutes ago, AJB2K3 said: Can I get some help please? Sure Firstly, your "command" is not complete. The mralligator page you are using lists "just" bare opcodes. Each of these, including any data byte(s), e.g., "0x01" for sound one, have to be followed by their two's complements (RCX uses: 0xFF - 8-bit opcode or 8-bit data byte as two's complement tc). Then the checksum needs to be appended, which are just the 8 low bits of the sum of all payload bytes (opcode + data bytes), excluding all two's complements, and lastly the two's complement of the checksum. Once you have coded the synthesizing of the entire data packet, it is all smooth and easy: preamble (0x55, 0xFF, 0x00), opcode, tc of opcode, data byte, tc of data byte, ..., checksum, tc of checksum. That is one full RCX command. Don't forget to flip the toggle bit of the opcode, when resending the command. When you scroll down on this post to the "Protocol bit/byte streams encoding" of old LEGO protocols, you'll find details for the RCX in section 4: Best Thorsten Quote
AJB2K3 Posted 5 hours ago Posted 5 hours ago (edited) 11 hours ago, Toastie said: Sure Firstly, your "command" is not complete. The mralligator page you are using lists "just" bare opcodes. Each of these, including any data byte(s), e.g., "0x01" for sound one, have to be followed by their two's complements (RCX uses: 0xFF - 8-bit opcode or 8-bit data byte as two's complement tc). Then the checksum needs to be appended, which are just the 8 low bits of the sum of all payload bytes (opcode + data bytes), excluding all two's complements, and lastly the two's complement of the checksum. Once you have coded the synthesizing of the entire data packet, it is all smooth and easy: preamble (0x55, 0xFF, 0x00), opcode, tc of opcode, data byte, tc of data byte, ..., checksum, tc of checksum. That is one full RCX command. Don't forget to flip the toggle bit of the opcode, when resending the command. When you scroll down on this post to the "Protocol bit/byte streams encoding" of old LEGO protocols, you'll find details for the RCX in section 4: Best Thorsten Thank you for your patience. The next question is on the complimentary bytes. how are these known, I’m confused over the issue of working them out dispute having read the docs. so the special bit on the end after the checksum needs to be “flipped” it a command is repeated on and then off so like in the case off remote control where the control button is held down or “button bashed” to make it continue to drive in one direction. sorry I have a brain ache from all this braining and need to keep repeating to get things to stick Edited 5 hours ago by AJB2K3 Quote
AJB2K3 Posted 4 hours ago Posted 4 hours ago Oh is that why MrAligator has two bytes listed on his listing? one being the command and the other being the complimentary byte? Quote
Toastie Posted 1 hour ago Posted 1 hour ago 1 hour ago, AJB2K3 said: one being the command and the other being the complimentary byte? Not exactly ... but close: The two's complement is what follows each message byte = opcode and databyte(s). The preamble is always 0x55, 0xFF, 0x00. For the PlaySound opcode (59) the two's complement is 0xFF-0x59=0xA6. Then you send the data byte, let's say for sound 1, and its two's complement 0xFF-0x01=0xFE. Next is the checksum and its two's complement. Checksum for 0x59+0x01=0x5A (only the lower 8 bits are sent, in this case not necessary to strip any high bits), the two's complement is 0xFF-0x5A=0xA5 The entire message for "PlaySound 1" should thus be 0x55, 0xFF, 0x00, 0x59, 0xA6, 0x01, 0xFE, 0x5A, 0xA5 Now, when you want to send "PlaySound 1" again right after the previous "PlaySound 1" or even repeatedly, you have to "toggle" bit #4 (0x08) in the opcode: 0x59-0x08=0x51 and vice versa. This of course also changes the complement of the opcode as well as the checksum and should be: 0x55, 0xFF, 0x00, 0x51, 0xAE, 0x01, 0xFE, 0x52, 0xAD. When you send another command after the first "PlaySound 1" message, you don't need to change the toggle bit. Here is how I assemble my RCX messages (I am using a pure SetMessage protocol for my RCX equipped trains, which is simply train ID + action = 2x consecutive SetMessages), so the first 5 bytes in each message are always the same (preamble + opcode SetMessage + two's complement = 0x55, 0xFF, 0x00, 0xF7, 0x08) then I simply append the message byte. Note that SetMessage (opcode 0xF7) does not need to change the toggle bit, when sending it twice or multiple times: const uint8_t RCXMessageHeader[5] = {0x55,0xFF,0x00,0xF7,0x08}; if (Flag_ComMode == ManualMode){ // Build full RCX message from ID and databyte manually entered for (int i=0; i<5; i++) ZXBytes[i] = RCXMessageHeader[i]; // Preamble + command message //ZXBytes[5] = ID; // From ManualInput. ZXBytes[6] = 0xFF-ZXBytes[5]; // RCX' two's complement ZXBytes[7] = lowByte(0xF7+ZXBytes[5]); // checksum of "real" data bytes in msg ZXBytes[8] = 0xFF-ZXBytes[7]; // RCX' two's complement for (int i=9; i<14; i++) ZXBytes[i] = RCXMessageHeader[i-9]; // Preamble + command message //ZXBytes[14] = databyte; // From ManualInput. ZXBytes[15] = 0xFF-ZXBytes[14]; // RCX' two's complement ZXBytes[16] = lowByte(0xF7+ZXBytes[14]); // checksum of "real" data bytes in msg ZXBytes[17] = 0xFF-ZXBytes[16]; // RCX' two's complement } Forgive me my horrible C++ coding - I am a BASIC person, so I code C++ as if it were BASIC Let me know whether this works (the PlaySound messages) - I started all this more than 25 years ago using MS QBASIC. I still have these programs on my laptop (Win11/64bit - using DOSBox-X) and my IBM XT (PCDOS 3.2) ; they run well on both machines. If not, I shall break out my test RCX, the IR tower and check. Could be that I screwed up the hex numbers above ... Best Thorsten Quote
AJB2K3 Posted 1 hour ago Posted 1 hour ago 15 minutes ago, Toastie said: Not exactly ... but close: The two's complement is what follows each message byte = opcode and databyte(s). The preamble is always 0x55, 0xFF, 0x00. For the PlaySound opcode (59) the two's complement is 0xFF-0x59=0xA6. Then you send the data byte, let's say for sound 1, and its two's complement 0xFF-0x01=0xFE. Next is the checksum and its two's complement. Checksum for 0x59+0x01=0x5A (only the lower 8 bits are sent, in this case not necessary to strip any high bits), the two's complement is 0xFF-0x5A=0xA5 The entire message for "PlaySound 1" should thus be 0x55, 0xFF, 0x00, 0x59, 0xA6, 0x01, 0xFE, 0x5A, 0xA5 Now, when you want to send "PlaySound 1" again right after the previous "PlaySound 1" or even repeatedly, you have to "toggle" bit #4 (0x08) in the opcode: 0x59-0x08=0x51 and vice versa. This of course also changes the complement of the opcode as well as the checksum and should be: 0x55, 0xFF, 0x00, 0x51, 0xAE, 0x01, 0xFE, 0x52, 0xAD. When you send another command after the first "PlaySound 1" message, you don't need to change the toggle bit. Here is how I assemble my RCX messages (I am using a pure SetMessage protocol for my RCX equipped trains, which is simply train ID + action = 2x consecutive SetMessages), so the first 5 bytes in each message are always the same (preamble + opcode SetMessage + two's complement = 0x55, 0xFF, 0x00, 0xF7, 0x08) then I simply append the message byte. Note that SetMessage (opcode 0xF7) does not need to change the toggle bit, when sending it twice or multiple times: const uint8_t RCXMessageHeader[5] = {0x55,0xFF,0x00,0xF7,0x08}; if (Flag_ComMode == ManualMode){ // Build full RCX message from ID and databyte manually entered for (int i=0; i<5; i++) ZXBytes[i] = RCXMessageHeader[i]; // Preamble + command message //ZXBytes[5] = ID; // From ManualInput. ZXBytes[6] = 0xFF-ZXBytes[5]; // RCX' two's complement ZXBytes[7] = lowByte(0xF7+ZXBytes[5]); // checksum of "real" data bytes in msg ZXBytes[8] = 0xFF-ZXBytes[7]; // RCX' two's complement for (int i=9; i<14; i++) ZXBytes[i] = RCXMessageHeader[i-9]; // Preamble + command message //ZXBytes[14] = databyte; // From ManualInput. ZXBytes[15] = 0xFF-ZXBytes[14]; // RCX' two's complement ZXBytes[16] = lowByte(0xF7+ZXBytes[14]); // checksum of "real" data bytes in msg ZXBytes[17] = 0xFF-ZXBytes[16]; // RCX' two's complement } Forgive me my horrible C++ coding - I am a BASIC person, so I code C++ as if it were BASIC Let me know whether this works (the PlaySound messages) - I started all this more than 25 years ago using MS QBASIC. I still have these programs on my laptop (Win11/64bit - using DOSBox-X) and my IBM XT (PCDOS 3.2) ; they run well on both machines. If not, I shall break out my test RCX, the IR tower and check. Could be that I screwed up the hex numbers above ... Best Thorsten Thanks, I’ll have a play when back at the computer. I don’t do c++ I’m a python user as I can’t handle c! 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.