MX-12W Servo Library

Dependents:   DISCO_L475VG_IOT01-Sensors-BSP

MX12.cpp

Committer:
tsoul
Date:
2021-04-16
Revision:
5:4bdd101ce4ec
Parent:
4:9ffc4009a463

File content as of revision 5:4bdd101ce4ec:

#include "MX12.h"

MX12::MX12(PinName tx, PinName rx, int baud) : _mx12(tx, rx) {
	// Serial configuration
	_mx12.baud(baud);
	_mx12.format(8, SerialBase::None, 1);
	_mx12.attach(callback(this, &MX12::_ReadCallback), SerialBase::RxIrq);

	// Internal defaults
	_sstate = SerialState::Idling;
	_pstate = ParsingState::Header;
}

void MX12::SetSpeed(unsigned char mot_id, float speed) {
	char data[2];

	// Speed absolute value
	int goal = (0x3ff * abs(speed));
 
	// Spin direction (CW is negative)
	if (speed < 0) {
		goal |= (0x1 << 10);
	}

	data[0] = goal & 0xff;
	data[1] = goal >> 8;
	
	// Send instruction
	_sstate = SerialState::Writing;
	rw(mot_id, 0x20, 2, data);
}

char MX12::IsAvailable(void) {
	return (_sstate == SerialState::Idling);
}

void MX12::rw(unsigned char mot_id, char adress, char len, char *data) {
	_answer = 0;
	memset(_current_frame.data, 0, MX12_DATA_MAX_SIZE);

	// Forge packet
	char cmd[16];
	
	cmd[0] = 0xff;
	cmd[1] = 0xff;
	cmd[4] = 0x02 + (data != NULL);
	
	cmd[2] = mot_id;
	
	if(data == NULL) cmd[3] = 4;
	else cmd[3] = 3 + len;
	
	cmd[5] = adress;
	
	// Compute checksum
	if(data == NULL) {
		cmd[6] = len;
		cmd[7] = 0xFF - (mot_id + 4 + 2 + adress + len);
		
		// Force length to one to force send
		len = 1;
	} else {
		char cs = mot_id + len + adress + 6;
		
		for(char i = 0; i < len; i++) {
			cmd[6 + i] = data[i];
			cs += data[i];
		}
		
		cmd[6 + len] = 0xFF - cs;
	}
	
	// Send packet
	if(mot_id != 0xFE) {
		for(char i = 0; i < (7 + len); i++) {
			_mx12.write(&cmd[i], 1);
		}
	}
}

void MX12::PrintSerial() {
	for(int i = 0; i < _frame_pointer; i++) {
		printf("%x ", _stored_frame[i]);
	}

	printf("\n");
}

MX12::Status MX12::GetStatus() {
	// Return the corresponding status code
	switch(_current_frame.data[0]) {
		case 0:
			return Ok;
			break;
		case 1 << 0:
			return InputVoltageError;
			break;
		case 1 << 1:
			return AngleLimitError;
			break;
		case 1 << 2:
			return OverheatingError;
			break;
		case 1 << 3:
			return RangeError;
			break;
		case 1 << 4:
			return ChecksumError;
			break;
		case 1 << 5:
			return OverloadError;
			break;
		case 1 << 6:
			return InstructionError;
			break;
		default:
			return Unknown;
	}
}

void MX12::_ReadCallback() {
	char c;
	
	// Try to read serial
	if(_mx12.read(&c, 1)) {
		_stored_frame[_frame_pointer++] = c;
		_scontext.checksum += c;

		// State-machine parsing
		switch(_pstate) {
			case Header:
				if(++(_scontext.headingCount) >= 2) {
					_scontext.headingCount = 0;
					_pstate = Id;
				}

				_scontext.checksum -= c;
				break;
			
			case Id:
				_current_frame.motorId = c;
				_pstate = Length;
				break;

			case Length:
				_current_frame.length = c - 1;
				_pstate = Data;
				break;

			case Data:
				_current_frame.data[_scontext.dataCount] = c;
				
				if(++(_scontext.dataCount) >= _current_frame.length) {
					_scontext.dataCount = 0;
					_pstate = Checksum;
				}
				break;
			
			case Checksum:
				_current_frame.valid = (_scontext.checksum == 0xFF);
				_scontext.checksum = 0;
				_pstate = Header;
				if(_answer) _sstate = Idling;
				_answer = 1;
				break;
		}
	}
}