imurvai / brickcontroller2

Cross platform application for controlling Lego creations using a bluetooth gamepad.
104 stars 28 forks source link

Support for Mould King Hub #91

Open ernprivado opened 1 year ago

ernprivado commented 1 year ago

Hi I notice that there is no support for mould king hub. I was just wondering if there is a plan for it

elclaudio commented 1 month ago

Heureka! :)

I managed to send the proper telegrams with hcitool on my raspi - without knowing what I was doing...

sudo su

hciconfig hci0 up
hciconfig hci0 leadv 3

// switch MK6.0 to BT-Mode
hcitool -i hci0 cmd 08 0008 25 02 01 02 1b ff f0 ff 6D B6 43 CF 7E 8F 47 11 88 66 59 38 D1 7A AA 26 49 5E 13 14 15 16 17 18

// stop all channels
hcitool -i hci0 cmd 08 0008 25 02 01 02 1b ff f0 ff 6D B6 43 CF 7E 8F 47 11 84 66 59 38 D1 7A AA 34 67 4A 55 BF 15 16 17 18

// channel 1 fullspeed
hcitool -i hci0 cmd 08 0008 25 02 01 02 1b ff f0 ff 6d b6 43 cf 7e 8f 47 11 84 66 59 47 d1 7a aa 34 67 4a ed b7 15 16 17 18

Screenshot 2024-05-15 072432

hcitool -i hci0 cmd 08 0008 
length:     25 (hex!)
flags:      02 01 02
length:     1b
type:       ff (-> manufacturer specific)
company id: ff f0
data:       rest

Fantastic, you are a genius ! ;-) I confirm it work on my raspi zero w too !

when launching cmd for full speed, the motor run but make a stop at intervalls and go back to full speed. Do you believe it's related to advertisement speed ? all in all, this is a breakthrough, now a computer can drive any motor from a shell script or programming language !

J0EK3R commented 1 month ago

when launching cmd for full speed, the motor run but make a stop at intervalls and go back to full speed. Do you believe it's related to advertisement speed?

Yes, we have to increase the advertisement frequency.

I haven't tested it but i think Here is a link how to increase BLE advertisement is the solution.

elclaudio commented 1 month ago

when launching cmd for full speed, the motor run but make a stop at intervalls and go back to full speed. Do you believe it's related to advertisement frequency?

Yes, we have to increase the advertisement speed.

I haven't tested IT but i think Here is a link how to increase BLE advertisement is the solution.

Yep, instead of hciconfig hci0 leadv 3

I used this:


hcitool -i hci0 cmd 08 0008 25 02 01 02 1b ff f0 ff 6D B6 43 CF 7E 8F 47 11 88 66 59 38 D1 7A AA 26 49 5E 13 14 15 16 17 18
hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00
hcitool -i hci0 cmd 0x08 0x000a 01

the motor now run without pause ;-) perfect

Now, I need to write a function to build the correct sequence of hex for each case (channel, motor direction, motor power...)

J0EK3R commented 1 month ago

OK, that's fine :) Now you have to transfer the crypt-function from here to i.E. python (the function TryDecryptBruteForce) is not needed. All functions in this file are static - that's pretty easy to transfer - no OOP (object oriented programming). Then, to test, if you put the byte-arrays from MouldKing_6_0_Modul.cs in the crypt-function you have to get back the values in my comments. I think it would make sense to create a git repo for that so we can exchange code and knowhow ;) Could you create one?

elclaudio commented 1 month ago

OK, that's fine :) Now you have to transfer the crypt-function from here to i.E. python (the function TryDecryptBruteForce) is not needed. All functions in this file are static - that's pretty easy to transfer - no OOP (object oriented programming). Then, to test, if you put the byte-arrays from MouldKing_6_0_Modul.cs in the crypt-function you have to get back the values in my comments. I think it would make sense to create a git repo for that so we can exchange code and knowhow ;) Could you create one?

Please, excuse me, but I'm no programmer ;-(

However, I tried to convert code from C# to python with online tools, for now I came up with this, the code has no errors but the results arent what they should be :

import array
from pprint import pprint

# Define a byte array for Telegram Connect
telegram_connect = [0x6D, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x92]

telegram_base_device_a = [0x61, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9E]
telegram_base_device_b = [0x62, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9D]
telegram_base_device_c = [0x63, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9C]

Array_C1C2C3C4C5 = array.array('B', [0xC1, 0xC2, 0xC3, 0xC4, 0xC5])
MagicArray_37 = [0] * 37
MagicArray_63 = [0] * 63

def Crypt(rawDataArray):
    targetArrayLength = len(Array_C1C2C3C4C5) + len(rawDataArray) + 20

    targetArray = bytearray(targetArrayLength)
    targetArray[15] = 113
    targetArray[16] = 15
    targetArray[17] = 85

    for index in range(len(Array_C1C2C3C4C5)):
        targetArray[index + 18] = Array_C1C2C3C4C5[(len(Array_C1C2C3C4C5) - index) - 1]

    targetArray[18 + len(Array_C1C2C3C4C5):] = rawDataArray

    for index in range(15, len(Array_C1C2C3C4C5) + 18):
        targetArray[index] = revert_bits_byte(targetArray[index])

    checksum = calc_checksum_from_arrays(Array_C1C2C3C4C5, rawDataArray)
    targetArray[len(Array_C1C2C3C4C5) + 18 + len(rawDataArray):] = [(checksum & 255), ((checksum >> 8) & 255)]

    magicNumberArray_63 = MagicArray_63.copy()
    tempArrayLength = targetArrayLength - 18
    tempArray = targetArray[18:].copy()

    crypt_array(tempArray, magicNumberArray_63)
    targetArray[18:] = tempArray

    magicNumberArray_37 = MagicArray_37.copy()
    crypt_array(targetArray, magicNumberArray_37)

    telegramArray = bytearray(24)

    lengthResultArray = len(Array_C1C2C3C4C5) + len(rawDataArray) + 5
    telegramArray[:lengthResultArray] = targetArray[15:15 + lengthResultArray]

    for index in range(lengthResultArray, len(telegramArray)):
        telegramArray[index] = index + 1

    return telegramArray

def create_magic_array(magic_number, size):
    magic_array = [0] * size
    magic_array[0] = 1

    for index in range(1, 7):
        magic_array[index] = (magic_number >> (6 - index)) & 1

    return magic_array

def revert_bits_int(value):
    result = 0
    for index_bit in range(16):
        if ((1 << index_bit) & value) != 0:
            result |= 1 << (15 - index_bit)
    return 65535 & result

def crypt_array(byte_array, magic_number_array):
    # foreach byte of array
    for index_byte in range(len(byte_array)):
        current_byte = byte_array[index_byte]
        current_result = 0
        # foreach bit in byte
        for index_bit in range(8):
            current_result += (((current_byte >> index_bit) & 1) ^ shift_magic_array(magic_number_array)) << index_bit
        byte_array[index_byte] = current_result & 255
    return byte_array

def calc_checksum_from_arrays(first_array, second_array):
    result = 65535
    for first_array_index in range(len(first_array)):
        result = (result ^ (first_array[(len(first_array) - 1) - first_array_index] << 8)) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    for current_byte in second_array:
        result = ((revert_bits_byte(current_byte) << 8) ^ result) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    return revert_bits_int(result) ^ 65535

def shift_magic_array(i_arr):
    # i_arr[3] = i_arr[2]
    # i_arr[2] = i_arr[1]
    # i_arr[1] = i_arr[0]
    # i_arr[0] = i_arr[6]
    # i_arr[6] = i_arr[5]
    # i_arr[5] = i_arr[4]
    # i_arr[4] = i_arr[3] ^ i_arr[6]
    # return i_arr[0]

    r0 = 3
    r1 = i_arr[r0]
    r2 = 6
    r3 = i_arr[r2]
    r1 = r1 ^ r3
    r3 = 2
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = 1
    r4 = i_arr[r0]
    i_arr[r3] = r4
    r3 = 0
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = i_arr[r2]
    i_arr[r3] = r0
    r0 = 5
    r4 = i_arr[r0]
    i_arr[r2] = r4
    r2 = 4
    r4 = i_arr[r2]
    i_arr[r0] = r4
    i_arr[r2] = r1
    r6 = i_arr[r3]
    return r6

def revert_bits_byte(value):
    result = 0
    for index_bit in range(8):
        if ((1 << index_bit) & value) != 0:
            result = result | (1 << (7 - index_bit))
    return result

pprint(Crypt(telegram_connect))

the results returned :

>>> %Run MouldKingCrypt.py
bytearray(b'\x8e\xf0\xaa\xa3#\xc3C\x83m{\xa7\x80\x80\x80\x80\x92'
          b'\xae\x8a\x13\x14\x15\x16\x17\x18')
J0EK3R commented 1 month ago

...only a quick review - I don't have time till saturday: MagicArray_37 and MagicArray_63 aren't properly initialized

Insider the Crypt function you can replace

magicNumberArray_63 = MagicArray_63.copy()
magicNumberArray_37 = MagicArray_37.copy()

with

magicNumberArray_63 = create_magic_array(63, 7)
magicNumberArray_37 = create_magic_array(37, 7)

and delete

MagicArray_37 = [0] * 37
MagicArray_63 = [0] * 63
J0EK3R commented 1 month ago

Here is a running version of your code

#!/usr/bin/python

import array
from pprint import pprint

# Define a byte array for Telegram Connect
telegram_connect = [0x6D, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x92]

telegram_base_device_a = [0x61, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9E]
telegram_base_device_b = [0x62, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9D]
telegram_base_device_c = [0x63, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9C]

Array_C1C2C3C4C5 = [0xC1, 0xC2, 0xC3, 0xC4, 0xC5]

def Crypt(rawDataArray):
    targetArrayLength = len(Array_C1C2C3C4C5) + len(rawDataArray) + 20

    targetArray = bytearray(targetArrayLength)
    targetArray[15] = 113
    targetArray[16] = 15
    targetArray[17] = 85

    for index in range(len(Array_C1C2C3C4C5)):
        targetArray[index + 18] = Array_C1C2C3C4C5[(len(Array_C1C2C3C4C5) - index) - 1]

    targetArray[18 + len(Array_C1C2C3C4C5):] = rawDataArray

    for index in range(15, len(Array_C1C2C3C4C5) + 18):
        targetArray[index] = revert_bits_byte(targetArray[index])

    checksum = calc_checksum_from_arrays(Array_C1C2C3C4C5, rawDataArray)
    targetArray[len(Array_C1C2C3C4C5) + 18 + len(rawDataArray):] = [(checksum & 255), ((checksum >> 8) & 255)]

    magicNumberArray_63 = create_magic_array(63, 7)
    tempArrayLength = targetArrayLength - 18
    tempArray = targetArray[18:].copy()

    crypt_array(tempArray, magicNumberArray_63)
    targetArray[18:] = tempArray

    magicNumberArray_37 = create_magic_array(37, 7)
    crypt_array(targetArray, magicNumberArray_37)

    telegramArray = bytearray(24)

    lengthResultArray = len(Array_C1C2C3C4C5) + len(rawDataArray) + 5
    telegramArray[:lengthResultArray] = targetArray[15:15 + lengthResultArray]

    for index in range(lengthResultArray, len(telegramArray)):
        telegramArray[index] = index + 1

    return telegramArray

def create_magic_array(magic_number, size):
    magic_array = [0] * size
    magic_array[0] = 1

    for index in range(1, 7):
        magic_array[index] = (magic_number >> (6 - index)) & 1

    return magic_array

def revert_bits_int(value):
    result = 0
    for index_bit in range(16):
        if ((1 << index_bit) & value) != 0:
            result |= 1 << (15 - index_bit)
    return 65535 & result

def crypt_array(byte_array, magic_number_array):
    # foreach byte of array
    for index_byte in range(len(byte_array)):
        current_byte = byte_array[index_byte]
        current_result = 0
        # foreach bit in byte
        for index_bit in range(8):
            current_result += (((current_byte >> index_bit) & 1) ^ shift_magic_array(magic_number_array)) << index_bit
        byte_array[index_byte] = current_result & 255
    return byte_array

def calc_checksum_from_arrays(first_array, second_array):
    result = 65535
    for first_array_index in range(len(first_array)):
        result = (result ^ (first_array[(len(first_array) - 1) - first_array_index] << 8)) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    for current_byte in second_array:
        result = ((revert_bits_byte(current_byte) << 8) ^ result) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    return revert_bits_int(result) ^ 65535

def shift_magic_array(i_arr):
    # i_arr[3] = i_arr[2]
    # i_arr[2] = i_arr[1]
    # i_arr[1] = i_arr[0]
    # i_arr[0] = i_arr[6]
    # i_arr[6] = i_arr[5]
    # i_arr[5] = i_arr[4]
    # i_arr[4] = i_arr[3] ^ i_arr[6]
    # return i_arr[0]

    r0 = 3
    r1 = i_arr[r0]
    r2 = 6
    r3 = i_arr[r2]
    r1 = r1 ^ r3
    r3 = 2
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = 1
    r4 = i_arr[r0]
    i_arr[r3] = r4
    r3 = 0
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = i_arr[r2]
    i_arr[r3] = r0
    r0 = 5
    r4 = i_arr[r0]
    i_arr[r2] = r4
    r2 = 4
    r4 = i_arr[r2]
    i_arr[r0] = r4
    i_arr[r2] = r1
    r6 = i_arr[r3]
    return r6

def revert_bits_byte(value):
    result = 0
    for index_bit in range(8):
        if ((1 << index_bit) & value) != 0:
            result = result | (1 << (7 - index_bit))
    return result

# pprint(Crypt(telegram_connect))
result = Crypt(telegram_connect)
print(' '.join(f'{x:02x}' for x in result))

Output:

/home/pi/dev/mkconnect/test.py 
6d b6 43 cf 7e 8f 47 11 88 66 59 38 d1 7a aa 26 49 5e 13 14 15 16 17 18
elclaudio commented 1 month ago

I've corrected the code, now it work

import array
#from pprint import pprint
#import numpy as np

#np.set_printoptions(formatter={'int':hex})

# Define a byte array for Telegram Connect
telegram_connect = [0x6D, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x92]
telegram_base_device_a = [0x61, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9E]
telegram_base_device_b = [0x62, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9D]
telegram_base_device_c = [0x63, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9C]

Array_C1C2C3C4C5 = array.array('B', [0xC1, 0xC2, 0xC3, 0xC4, 0xC5])

def Crypt(rawDataArray):
    targetArrayLength = len(Array_C1C2C3C4C5) + len(rawDataArray) + 20

    targetArray = [0] * targetArrayLength
    targetArray[15] = 113 #0x71
    targetArray[16] = 15 #0x0F
    targetArray[17] = 85 #0x55

    for index in range(len(Array_C1C2C3C4C5)):
        targetArray[index + 18] = Array_C1C2C3C4C5[(len(Array_C1C2C3C4C5) - index) - 1]

    targetArray[18 + len(Array_C1C2C3C4C5):] = rawDataArray

    for index in range(15, len(Array_C1C2C3C4C5) + 18):
        targetArray[index] = revert_bits_byte(targetArray[index])

    checksum = calc_checksum_from_arrays(Array_C1C2C3C4C5, rawDataArray)
    targetArray[len(Array_C1C2C3C4C5) + 18 + len(rawDataArray):] = [(checksum & 255), ((checksum >> 8) & 255)]

    magicNumberArray_63 = create_magic_array(63, 7)
    tempArrayLength = targetArrayLength - 18
    tempArray = targetArray[18:].copy()

    crypt_array(tempArray, magicNumberArray_63)
    targetArray[18:] = tempArray

    magicNumberArray_37 = create_magic_array(37, 7)
    crypt_array(targetArray, magicNumberArray_37)

    telegramArray = [0] * 24

    lengthResultArray = len(Array_C1C2C3C4C5) + len(rawDataArray) + 5
    telegramArray[:lengthResultArray] = targetArray[15:15 + lengthResultArray]

    for index in range(lengthResultArray, len(telegramArray)):
        telegramArray[index] = index + 1

    return telegramArray

def create_magic_array(magic_number, size):
    magic_array = [0] * size
    magic_array[0] = 1

    for index in range(1, 7):
        magic_array[index] = (magic_number >> (6 - index)) & 1

    return magic_array

def revert_bits_int(value):
    result = 0
    for index_bit in range(16):
        if ((1 << index_bit) & value) != 0:
            result |= 1 << (15 - index_bit)
    return 65535 & result

def crypt_array(byte_array, magic_number_array):
    # foreach byte of array
    for index_byte in range(len(byte_array)):
        current_byte = byte_array[index_byte]
        current_result = 0
        # foreach bit in byte
        for index_bit in range(8):
            current_result += (((current_byte >> index_bit) & 1) ^ shift_magic_array(magic_number_array)) << index_bit
        byte_array[index_byte] = current_result & 255
    return byte_array

def calc_checksum_from_arrays(first_array, second_array):
    result = 65535
    for first_array_index in range(len(first_array)):
        result = (result ^ (first_array[(len(first_array) - 1) - first_array_index] << 8)) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    for current_byte in second_array:
        result = ((revert_bits_byte(current_byte) << 8) ^ result) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    return revert_bits_int(result) ^ 65535

def shift_magic_array(i_arr):
    # i_arr[3] = i_arr[2]
    # i_arr[2] = i_arr[1]
    # i_arr[1] = i_arr[0]
    # i_arr[0] = i_arr[6]
    # i_arr[6] = i_arr[5]
    # i_arr[5] = i_arr[4]
    # i_arr[4] = i_arr[3] ^ i_arr[6]
    # return i_arr[0]

    r0 = 3
    r1 = i_arr[r0]
    r2 = 6
    r3 = i_arr[r2]
    r1 = r1 ^ r3
    r3 = 2
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = 1
    r4 = i_arr[r0]
    i_arr[r3] = r4
    r3 = 0
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = i_arr[r2]
    i_arr[r3] = r0
    r0 = 5
    r4 = i_arr[r0]
    i_arr[r2] = r4
    r2 = 4
    r4 = i_arr[r2]
    i_arr[r0] = r4
    i_arr[r2] = r1
    r6 = i_arr[r3]
    return r6

def revert_bits_byte(value):
    result = 0
    for index_bit in range(8):
        if ((1 << index_bit) & value) != 0:
            result = result | (1 << (7 - index_bit))
    return result

print(Crypt(telegram_connect))
print(Crypt(telegram_base_device_a))
elclaudio commented 1 month ago

Here is a running version of your code

#!/usr/bin/python

import array
from pprint import pprint

# Define a byte array for Telegram Connect
telegram_connect = [0x6D, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x92]

telegram_base_device_a = [0x61, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9E]
telegram_base_device_b = [0x62, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9D]
telegram_base_device_c = [0x63, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9C]

Array_C1C2C3C4C5 = [0xC1, 0xC2, 0xC3, 0xC4, 0xC5]

def Crypt(rawDataArray):
    targetArrayLength = len(Array_C1C2C3C4C5) + len(rawDataArray) + 20

    targetArray = bytearray(targetArrayLength)
    targetArray[15] = 113
    targetArray[16] = 15
    targetArray[17] = 85

    for index in range(len(Array_C1C2C3C4C5)):
        targetArray[index + 18] = Array_C1C2C3C4C5[(len(Array_C1C2C3C4C5) - index) - 1]

    targetArray[18 + len(Array_C1C2C3C4C5):] = rawDataArray

    for index in range(15, len(Array_C1C2C3C4C5) + 18):
        targetArray[index] = revert_bits_byte(targetArray[index])

    checksum = calc_checksum_from_arrays(Array_C1C2C3C4C5, rawDataArray)
    targetArray[len(Array_C1C2C3C4C5) + 18 + len(rawDataArray):] = [(checksum & 255), ((checksum >> 8) & 255)]

    magicNumberArray_63 = create_magic_array(63, 7)
    tempArrayLength = targetArrayLength - 18
    tempArray = targetArray[18:].copy()

    crypt_array(tempArray, magicNumberArray_63)
    targetArray[18:] = tempArray

    magicNumberArray_37 = create_magic_array(37, 7)
    crypt_array(targetArray, magicNumberArray_37)

    telegramArray = bytearray(24)

    lengthResultArray = len(Array_C1C2C3C4C5) + len(rawDataArray) + 5
    telegramArray[:lengthResultArray] = targetArray[15:15 + lengthResultArray]

    for index in range(lengthResultArray, len(telegramArray)):
        telegramArray[index] = index + 1

    return telegramArray

def create_magic_array(magic_number, size):
    magic_array = [0] * size
    magic_array[0] = 1

    for index in range(1, 7):
        magic_array[index] = (magic_number >> (6 - index)) & 1

    return magic_array

def revert_bits_int(value):
    result = 0
    for index_bit in range(16):
        if ((1 << index_bit) & value) != 0:
            result |= 1 << (15 - index_bit)
    return 65535 & result

def crypt_array(byte_array, magic_number_array):
    # foreach byte of array
    for index_byte in range(len(byte_array)):
        current_byte = byte_array[index_byte]
        current_result = 0
        # foreach bit in byte
        for index_bit in range(8):
            current_result += (((current_byte >> index_bit) & 1) ^ shift_magic_array(magic_number_array)) << index_bit
        byte_array[index_byte] = current_result & 255
    return byte_array

def calc_checksum_from_arrays(first_array, second_array):
    result = 65535
    for first_array_index in range(len(first_array)):
        result = (result ^ (first_array[(len(first_array) - 1) - first_array_index] << 8)) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    for current_byte in second_array:
        result = ((revert_bits_byte(current_byte) << 8) ^ result) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    return revert_bits_int(result) ^ 65535

def shift_magic_array(i_arr):
    # i_arr[3] = i_arr[2]
    # i_arr[2] = i_arr[1]
    # i_arr[1] = i_arr[0]
    # i_arr[0] = i_arr[6]
    # i_arr[6] = i_arr[5]
    # i_arr[5] = i_arr[4]
    # i_arr[4] = i_arr[3] ^ i_arr[6]
    # return i_arr[0]

    r0 = 3
    r1 = i_arr[r0]
    r2 = 6
    r3 = i_arr[r2]
    r1 = r1 ^ r3
    r3 = 2
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = 1
    r4 = i_arr[r0]
    i_arr[r3] = r4
    r3 = 0
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = i_arr[r2]
    i_arr[r3] = r0
    r0 = 5
    r4 = i_arr[r0]
    i_arr[r2] = r4
    r2 = 4
    r4 = i_arr[r2]
    i_arr[r0] = r4
    i_arr[r2] = r1
    r6 = i_arr[r3]
    return r6

def revert_bits_byte(value):
    result = 0
    for index_bit in range(8):
        if ((1 << index_bit) & value) != 0:
            result = result | (1 << (7 - index_bit))
    return result

# pprint(Crypt(telegram_connect))
result = Crypt(telegram_connect)
print(' '.join(f'{x:02x}' for x in result))

Output:

/home/pi/dev/mkconnect/test.py 
6d b6 43 cf 7e 8f 47 11 88 66 59 38 d1 7a aa 26 49 5e 13 14 15 16 17 18

Oh thanks, sorry, I was looking at it in beetwen, I didn't see your post !

telegram_base_device_a seem to be the code for stopping the motors but how do you manage the choice of channel, rotation direction and motor's power ?

elclaudio commented 1 month ago

https://github.com/imurvai/brickcontroller2/assets/6136831/78c71be0-c5bd-4b8c-baab-36d14fdf9dc9

Many things to do yet, but very promising ! I will order a raspberry pi pico W (with embedded python interpreter and bluetooth) to test if that works too... but I have to find a way to bypass hcitool and send the commands directly to the integrated BT controller I hope it's possible on this device, if not I'll keep the raspi zero w.

Next step is to control channel selection, motor direction and motor power. After that, comes the nice part of using proximity sensor, color sensors and switchs via i2c which should be easy to do. In the end, why not make a pcb board with sensors connectors (i2c bus allow many peripherals on short distances with minimal cabling) and digital inputs (I think about magnetics dil relays, very cheap, and others simple mecanicals switchs, all those can act as limit switch)

I have another mould king 6.0 hub on order plus a bunch of motors to make tests

edit: it seems that there is issues for running on raspi pico : micropython instead of python

there is a simulator here (same error on real device) : https://wokwi.com/projects/new/micropython-pi-pico pasting the very same code is not working, I didn't had time to look at it more precisely


Traceback (most recent call last):
  File "main.py", line 143, in <module>
  File "main.py", line 23, in Crypt
NotImplementedError: array/bytes required on right side
J0EK3R commented 1 month ago

Oh, i found something interesting: hcitool has been deprecated

elclaudio commented 1 month ago

edit: it seems that there is issues for running on raspi pico : micropython instead of python

there is a simulator here (same error on real device) : https://wokwi.com/projects/new/micropython-pi-pico pasting the very same code is not working, I didn't had time to look at it more precisely


Traceback (most recent call last):
  File "main.py", line 143, in <module>
  File "main.py", line 23, in Crypt
NotImplementedError: array/bytes required on right side

I've corrected the code for the pico, now it appear to run correctly 👍

ps : just for reference, I found this code exemple for BT advertising on the pico controller: https://github.com/raspberrypi/pico-micropython-examples/blob/master/bluetooth/ble_advertising.py

#import array
import sys
import time
try:
    from ulab import numpy as np
except ImportError:
    import numpy as np

np.set_printoptions(threshold=1000)

#telegram_connect = np.array([0x6D, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x92])
#telegram_base_device_a = np.array([0x61, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9E])
#telegram_base_device_b = np.array([0x62, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9D], dtype=np.uint8)
#telegram_base_device_c = np.array([0x63, 0x7B, 0xA7, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x9C], dtype=np.uint8)
#Array_C1C2C3C4C5 = np.array([0xC1, 0xC2, 0xC3, 0xC4, 0xC5])

# Define a byte array for Telegram Connect
telegram_connect = np.array([109, 123, 167, 128, 128, 128, 128, 146], dtype=np.uint8)
telegram_base_device_a = np.array([97, 123, 167, 128, 128, 128, 128, 128, 128, 158], dtype=np.uint8)
telegram_base_device_b = np.array([98, 123, 167, 128, 128, 128, 128, 128, 128, 157], dtype=np.uint8)
telegram_base_device_c = np.array([99, 123, 167, 128, 128, 128, 128, 128, 128, 156], dtype=np.uint8)
Array_C1C2C3C4C5 = np.array([193, 194, 195, 196, 197], dtype=np.uint8)

def Crypt(rawDataArray):
    # targetArrayLength should be 5+8+20 = 33 for connect
    targetArrayLength = len(Array_C1C2C3C4C5) + len(rawDataArray) + 20

    #targetArray = bytearray(targetArrayLength)
    targetArray = np.zeros(targetArrayLength, dtype=np.uint8)
    targetArray[15] = 113
    targetArray[16] = 15
    targetArray[17] = 85

    for index in range(len(Array_C1C2C3C4C5)):
        targetArray[index + 18] = Array_C1C2C3C4C5[(len(Array_C1C2C3C4C5) - index) - 1]

    for index in range(len(rawDataArray)):
        targetArray[18 + len(Array_C1C2C3C4C5) + index] = rawDataArray[index]

    for index in range(15, len(Array_C1C2C3C4C5) + 18):
        targetArray[index] = revert_bits_byte(targetArray[index])

    checksum = calc_checksum_from_arrays(Array_C1C2C3C4C5, rawDataArray)
    targetArray[len(Array_C1C2C3C4C5) + 18 + len(rawDataArray):] = [(checksum & 255), ((checksum >> 8) & 255)]

    magicNumberArray_63 = create_magic_array(63, 7)
    tempArrayLength = targetArrayLength - 18
    tempArray = targetArray[18:].copy()

    crypt_array(tempArray, magicNumberArray_63)
    targetArray[18:] = tempArray

    magicNumberArray_37 = create_magic_array(37, 7)
    crypt_array(targetArray, magicNumberArray_37)

    telegramArray = np.zeros(24, dtype=np.uint8)

    lengthResultArray = len(Array_C1C2C3C4C5) + len(rawDataArray) + 5
    telegramArray[:lengthResultArray] = targetArray[15:15 + lengthResultArray]

    for index in range(lengthResultArray, len(telegramArray)):
        telegramArray[index] = index + 1

    return telegramArray

def create_magic_array(magic_number, size):
    magic_array = [0] * size
    magic_array[0] = 1

    for index in range(1, 7):
        magic_array[index] = (magic_number >> (6 - index)) & 1

    return magic_array

def revert_bits_int(value):
    result = 0
    for index_bit in range(16):
        if ((1 << index_bit) & value) != 0:
            result |= 1 << (15 - index_bit)
    return 65535 & result

def crypt_array(byte_array, magic_number_array):
    # foreach byte of array
    for index_byte in range(len(byte_array)):
        current_byte = byte_array[index_byte]
        current_result = 0
        # foreach bit in byte
        for index_bit in range(8):
            current_result += (((current_byte >> index_bit) & 1) ^ shift_magic_array(magic_number_array)) << index_bit
        byte_array[index_byte] = current_result & 255
    return byte_array

def calc_checksum_from_arrays(first_array, second_array):
    result = 65535
    for first_array_index in range(len(first_array)):
        result = (result ^ (first_array[(len(first_array) - 1) - first_array_index] << 8)) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    for current_byte in second_array:
        result = ((revert_bits_byte(current_byte) << 8) ^ result) & 65535
        for index_bit in range(8):
            current_result = result & 32768
            result <<= 1
            if current_result != 0:
                result ^= 4129

    return revert_bits_int(result) ^ 65535

def shift_magic_array(i_arr):
    # i_arr[3] = i_arr[2]
    # i_arr[2] = i_arr[1]
    # i_arr[1] = i_arr[0]
    # i_arr[0] = i_arr[6]
    # i_arr[6] = i_arr[5]
    # i_arr[5] = i_arr[4]
    # i_arr[4] = i_arr[3] ^ i_arr[6]
    # return i_arr[0]

    r0 = 3
    r1 = i_arr[r0]
    r2 = 6
    r3 = i_arr[r2]
    r1 = r1 ^ r3
    r3 = 2
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = 1
    r4 = i_arr[r0]
    i_arr[r3] = r4
    r3 = 0
    r4 = i_arr[r3]
    i_arr[r0] = r4
    r0 = i_arr[r2]
    i_arr[r3] = r0
    r0 = 5
    r4 = i_arr[r0]
    i_arr[r2] = r4
    r2 = 4
    r4 = i_arr[r2]
    i_arr[r0] = r4
    i_arr[r2] = r1
    r6 = i_arr[r3]
    return r6

def revert_bits_byte(value):
    result = 0
    for index_bit in range(8):
        if ((1 << index_bit) & value) != 0:
            result = result | (1 << (7 - index_bit))
    return result

result = Crypt(telegram_connect)
result2 = Crypt(telegram_base_device_a)
print(' '.join(f'{x:02X}' for x in result))
print(' '.join(f'{x:02X}' for x in result2))
J0EK3R commented 1 month ago

@elclaudio I have created the repo mkconnect-python. I suggest to continue the discussion there... :)