Wednesday, May 23, 2018

Jogo da Velha em python

import  sys
#Variaveis Globais#

matriz = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
jogadores = -1
flag = 1
def verifica_potuacao(arena,jog):
    for i in range(3):
        soma = 0        for j in range(3):
            soma = soma  + arena[i][j]
        if (soma == 3):
            print("Jogador 1 ganhou")
            sys.exit()
        if (soma == -3):
            print("Jogador 2 ganhou")
            sys.exit()
    for j in range(3):
        soma = 0        for i in range(3):
            soma = soma + arena[i][j]
        if (soma == 3):
            print("Jogador 1 ganhou")
            sys.exit()
        if (soma == -3):
            print("Jogador 2 ganhou")
            sys.exit()

    if (arena[0][0]+arena[1][1]+arena[2][2]) == 3:
            print("Jogador 1 ganhou")
            sys.exit()
    if (arena[0][0]+arena[1][1]+arena[2][2]) == -3:
            print("Jogador 2 ganhou")
            sys.exit()
    if (arena[2][0]+arena[1][1]+arena[0][2]) == 3:
            print("Jogador 1 ganhou")
            sys.exit()
    if (arena[2][0]+arena[1][1]+arena[0][2]) == -3:
            print("Jogador 2 ganhou")
            sys.exit()
def jogada(arena,jog,flag):
    for i in range(3):
        for j in range(3):
            if (arena[i][j]) ==0:
                verifica_potuacao(arena, jog)
                jogador(arena, jog, flag)
    verifica_potuacao(arena, jog)
    print("Jogo empatou")
    sys.exit()

def jogador(arena,jog,flag):
    if (flag == 1):
        if jog == -1:
            jog = 1            print("Primeiro Jogador a jogar")
            print(matriz[0])
            print(matriz[1])
            print(matriz[2])
        else:
            jog = -1            print("Segundo Jogador a jogar")
            print(matriz[0])
            print(matriz[1])
            print(matriz[2])
    num = input("Escolha uma zona")
    if (num == '1'):
        if (arena[2][0] == 0):
            arena[2][0] = jog
        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena,jog,flag)

    if num == '2':
        if (arena[2][1] == 0):
            arena[2][1] = jog
        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)

    if num == '3':
        if (arena[2][2] == 0):
            arena[2][2] = jog
        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)
    if num == '4':
        if (arena[1][0] == 0):
            arena[1][0] = jog

        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)

    if num == '5':
        if (arena[1][1] == 0):
            arena[1][1] = jog

        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)
    if num == '6':
        if (arena[1][2] == 0):
            arena[1][2] = jog

        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)

    if num == '7':
        if (arena[0][0] == 0):
            arena[0][0] = jog

        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog,flag)
    if num == '8':
        if (arena[0][1] == 0):
            arena[0][1] = jog

        else:
            print("Selecione outra zona")
            flag = 0            jogador(arena, jog, flag)
    if num == '9':
        if (arena[0][2] == 0):
            arena[0][2] = jog

    if (num != '1' and num != '2' and num != '3' and
 num != '4'and num != '5'and num != '6'and num != '7' and
 num != '8'and num != '9') :
        print("Valo indisponivel")
        if num == '':
            print("Por favor digite um valor e tente novamente")
            
        flag = 1        if jog == -1:
            jog = 1        else:
            jog = -1        jogador(arena, jog, flag)

    print(matriz[0])
    print(matriz[1])
    print(matriz[2])
    flag = 1    jogada(arena,jog,flag)
#Gatilho para iniciar o jogo

jogada(matriz,jogadores,flag)
Share:

Thursday, December 28, 2017

Brincando um pouco com PYTHON + MYSQL + ARDUINO


Banco recebendo valores do Arduíno via Python....A estampa de tempo é dada pelo Python :/

IDE utilizada...o nosso amigo PyCharm




Então pessoas, o código esta bem extenso,eu admito que poderia te-lo deixado menor, mais diante
de um problema de saúde ( e muito stress....)consegui fazer o que pretendia,uma interface de
comunicação entre um dispositivo do tipo serial(RS232.... bom, não interessa muito o meio físico),
se comunicando a um banco relacional que esta em uma rede de internet. Em breve postarei um versão melhor e atualizada do código...


import serial

import pymysql
from builtins import print
from datetime import datetime


# ---------------------------Variaveis Global----------------------------------------------------#
indice_1 = "temperatura"indice_2 = "nivel"indice_3 = "vazao"indice_4 = "pressao"rg = '0123456789'condicao = TrueIntervalo = 0.1Tempo_Anterior = 0





#Tenta comunicação  inicial com Arduinotry:
    ser = serial.Serial(port='COM3', baudrate=9600,timeout='1')
    flag = 1except:
    print("Não há comunicação serial, tente novamente")
    flag = 0    while(flag == 0):
        try:
            ser = serial.Serial(port='COM3', baudrate=9600)
            flag = 1        except:
            print("Reconnecte o dispositivo...")

#Tenta comunicação inicial com Servidortry:
    conn = pymysql.connect(host='localhost', user='root', password='', db='cadastro')
    sql1 = conn.cursor()  # Inserir o TimeStamp e demais variaveis    sql1_1 = conn.cursor()  # consulta tempo    sql2_2 = conn.cursor()  # consulta temperatura    sql3_3 = conn.cursor()  # consulta nivel    sql4_4 = conn.cursor()  # consutla vazao    sql5_5 = conn.cursor()  # consulta pressao    flag2 = 1except:
    flag2 = 0    print("Não foi possivel se conectar ao banco de dados, restart o servidor.")
    while (flag2 == 0):
        try:
            conn = pymysql.connect(host='localhost', user='root', password='', db='cadastro')
            sql1 = conn.cursor()  # Inserir o TimeStamp e demais variaveis            sql1_1 = conn.cursor()  # consulta tempo            sql2_2 = conn.cursor()  # consulta temperatura            sql3_3 = conn.cursor()  # consulta nivel            sql4_4 = conn.cursor()  # consutla vazao            sql5_5 = conn.cursor()  # consulta pressao            flag2 = 1        except:
            print("Não foi possivel se conectar ao banco de dados, restart o servidor.")


while (True):
    now = str(datetime.now())
    palavra = ser.readline(40)
    teste = str('\_r\_n').replace("_", "")
    teste_2 = ("_'_").replace('_', "")
    texto = str(palavra).replace(teste, " ").replace('b', "").replace(teste_2,'') # valor deixa de existir apos o print    texto_Apenas = str(palavra).replace(teste, " ").replace('b', "").replace(teste_2, '')
    if indice_1 in texto_Apenas:
        temp = texto_Apenas
        for i in range(len(temp)):
            if temp[i] not in rg:
                temp = temp.replace(temp[i], " ")
                valor_temperatura = (temp).replace(" ", "")
                temperatura = valor_temperatura
    if indice_2 in texto_Apenas:
        niv = texto_Apenas
        for i in range(len(niv)):
            if niv[i] not in rg:
                niv = niv.replace(niv[i], " ")
                valor_nivel = (niv).replace(" ", "")
                nivel = valor_nivel
    if indice_3 in texto_Apenas:
        vaz = texto_Apenas
        for i in range(len(vaz)):
            if vaz[i] not in rg:
                vaz = vaz.replace(vaz[i], " ")
                valor_vazao = (vaz).replace(" ", "")
                vazao = valor_vazao
    if indice_4 in texto_Apenas:
        pres = texto_Apenas
        for i in range(len(pres)):
            if pres[i] not in rg:
                pres = pres.replace(pres[i], " ")
                valor_pressao = (pres).replace(" ", "")
                pressao = valor_pressao
    #Controle de tempo    now = str(datetime.now())
    Tempo_Segundo = datetime.now()
    Tempo_Atual = Tempo_Segundo.second
    Controle_Tempo = (Tempo_Atual - Tempo_Anterior)
    if (Controle_Tempo < Intervalo):
        Tempo_Anterior = Tempo_Segundo.second
    if (Controle_Tempo > Intervalo):
        Tempo_Anterior = Tempo_Segundo.second
        TimeStamp = datetime.utcnow().strftime('%Y-%m-%d  %H:%M:%S')
        try:
            sql1.execute('INSERT INTO `arduino` (data,temperatura,nivel,vazao,pressao) values( "' + TimeStamp + '",'+valor_temperatura+','+valor_nivel+','+valor_vazao+','+valor_pressao+')')
            sql1_1.execute('SELECT `data`  FROM `arduino` Order by `data` DESC LIMIT 1')
            sql2_2.execute('SELECT `temperatura`  FROM `arduino` Order by `data` DESC LIMIT 1')
            sql3_3.execute('SELECT `nivel`  FROM `arduino` Order by `data` DESC LIMIT 1')
            sql4_4.execute('SELECT `vazao`  FROM `arduino` Order by `data` DESC LIMIT 1')
            sql5_5.execute('SELECT `pressao`  FROM `arduino` Order by `data` DESC LIMIT 1')
            Data = sql1_1.fetchall()
            Temperatura = sql2_2.fetchall()
            Nivel = sql3_3.fetchall()
            Vazao = sql4_4.fetchall()
            Pressao = sql5_5.fetchall()
            print(str(Data).replace(',)', "").replace("((", ""))
            print("Valor de Temperatura: " + str(Temperatura).replace(',)', "").replace("((", ""))
            print("Valor de Nivel: " + str(Nivel).replace(',)', "").replace("((", ""))
            print("Valor de Vazao: " + str(Vazao).replace(',)', "").replace("((", ""))
            print("Valor de Pressao: " + str(Pressao).replace(',)', "").replace("((", ""))
        except:
            try:
                conn = pymysql.connect(host='localhost', user='root', password='', db='cadastro')
                sql1 = conn.cursor()  # Inserir o TimeStamp e demais variaveis                sql1_1 = conn.cursor()  # consulta tempo                sql2_2 = conn.cursor()  # consulta temperatura                sql3_3 = conn.cursor()  # consulta nivel                sql4_4 = conn.cursor()  # consutla vazao                sql5_5 = conn.cursor()  # consulta pressao            except:
                print("Erro na consulta, tentando se reconectar o Servidor")
Share:

Wednesday, August 23, 2017

Script em Python para solucionar problemas do teclado...


Então..... essa semana tive um problema serio com as teclas de meu teclado, repentinamente pararão de funcionar, por ser um teclado Bluetooth, não queria comprar outro no momento(Caro para meu padrão de vida :( ), então  unir duas lib's que encontrei na internet para  resolver esse problema.
 Resolução:
  Criei um script que simplesmente escreve uma tecla que eu habitualmente não uso, apague ela e escreve a tecla está quebrada ;) huswhushushsuhsu


from pynput import keyboard

import pyautogui

import sys


def on_press(key):
    try:
        k = key.char  # single-char keys
    except:
        k = key.name  # other keys
    if key == keyboard.Key.esc: return False  # stop listener
    if k in ['/']:  # keys interested
        print('Key pressed: ' + k)

        pyautogui.press('backspace')

        pyautogui.press('f')

    if k in ['*']:  # keys interested
        print('Key pressed: ' + k)

        pyautogui.press('backspace')

        pyautogui.press('j')

    if k in ['-']:  # keys interested
        print('Key pressed: ' + k)

        pyautogui.press('backspace')

        pyautogui.press('.')

    if k in ['+']:  # keys interested
        print('Key pressed: ' + k)

        pyautogui.press('backspace')

        pyautogui.press(',')

        return True
a = 1;
while a == 1:
    lis = keyboard.Listener(on_press)
    lis.start()
    lis.join()
Share:

Saturday, June 10, 2017

Joystick Master System + Arduíno + Python

Há vários anos, tive guardado em meu armário o controle de meu master system, (aquele da TecToy), então, tentei usa-lo no meu computador, conectando ao meu Arduíno e fazendo a interpretação dos botoes com Python para ele interagir com o windows.


Usei um código de leitura dos botoes do Joystick e mandei os valores direto para a serial para fazer a leitura via Python
Em meu código precisei usar bibliotecas auxiliares:



                  '-----------------------       libs       ------------------------------'
  • py_Serial: leitura da serial.
  • re :  encontrar as letras em minha serial, de forma mais eficiente.
  • pyautogui: interação do Python com windows.
  • win32com: interação do Python com windows, mais rápida que a pyautogui, contudo parou de responder, então tive que substitui-la
Código esta escrito abaixo não é lá grande coisa, mais por falta de pratica em programação fiz o máximo e pouco tempo.

Videos:



from ctypes import py_object
from json.encoder import py_encode_basestring_ascii
import serial
import re
#import win32com.clientimport time
import pyautogui

ser = serial.Serial()
ser.baudrate= 250000ser.port = 'COM9'ser.timeout = 5ser.open()
a = 1while a == 1:
    s = ser.read(15)
    l1 = re.findall('[A-Z]', s)
    nu = len(re.findall('[A-Z]', s))
    while l1 != []:
        if  nu == 1:
            b1 = l1[0]
            print("Tecla pressionada ", b1)
            pyautogui.press(b1)
            #win32com.client.Dispatch("WScript.Shell").SendKeys(b1)            ser.reset_input_buffer()
        if nu == 2:
            l1 = re.findall('[A-Z]', s)
            b1 = l1[0]
            b2 = l1[1]
            pyautogui.press(b1) and pyautogui.press(b2)
            #win32com.client.Dispatch("WScript.Shell").SendKeys(b1) and win32com.client.Dispatch("WScript.Shell").SendKeys(b2)            print("Teclas pressionadas ", b1, " e ", b2)
            ser.reset_input_buffer()
        if nu == 3:
            l1 = re.findall('[A-Z]', s)
            b1 = l1[0]
            b2 = l1[1]
            b3 = l1[2]
            #win32com.client.Dispatch("WScript.Shell").SendKeys(b1) and win32com.client.Dispatch("WScript.Shell").SendKeys(b2) and win32com.client.Dispatch("WScript.Shell").SendKeys(b3)            pyautogui.press(b1) and pyautogui.press(b2) and pyautogui.press(b3)
            print("Teclas pressionadas ", b1, " , ", b2," e ", b3)
        l1 = re.findall('[A-Z]',ser.read(15))
        ser.reset_input_buffer()
    print(l1)






Share:

Sunday, March 19, 2017

Acesso Lev da SARAIVA via SSH (security shell) OCIOSO

Sem nada para se fazer em casa, pesquisei maneiras de tirar todo o potencial do meu reader  LEV da (Saraiva), o qual uso para ler meus mangas e livros técnicos, pesquisando um pouco, achei uma maneira de acessa-lo utilizando o acesso do tipo SSH, é aquele acesso usado muito para entrar em servidor  através da porta 22,, quebrei um pouco a cabeça, mais consegui acessa-lo, não instalei nenhum tipo de aplicação, apenas modificações simples, como dimerizar a luminosidade da tela, mudar hostname, nada prejudicial, o acesso foi via rede, através do ip do mesmo.

No firmware atual seria impossível fazer o acesso SSH, pois não há um servidor SSH nesta versão, então foi necessário baixar o firmware do Odyssye, que é uma versão do linux 3.0.8 e que possui um servido rodando.


Utilizei o Putty para esse acesso, pois não tinha um terminal linux a minha disposição.

Login padrão para acesso é root, password padrão é : root


Assim posso obter todas as informações do dispositivo, assim como aquivos, funções, como por exemplo acender a luz interna do reader e outras.










Share:

Wednesday, May 25, 2016

Projeto Alternate Body (AB)



Supervisório desenvolvido em JAVA:






Vídeo Final:





Primeiro Protótipo:





Luva tátil para deficiente visuais. 


O objetivo da Alternate Body  é criar dispositivos e próteses  que facilitem a vida das pessoas quem  possuem algum tipo de deficiência, objetivando alcançar pessoas carentes que não possuem uma renda mensal que possa pagar por algo do gênero.
 Nosso objetivo principal é a produção de próteses adaptadas ao seu usuário,  melhorar a qualidade, tentando otimizar ao máximo o custo de fabricação, unificar sistemas supervisórios das próteses para que o usuário tenha acesso a analise total  do seu dispositivo, via celular ou computador.

Versão final, com um sensor LDR para futuras modificações, um adaptador para baterias de 9V, ficou enorme, mais funcional.

Protótipo Final:



















Share:

Thursday, May 19, 2016

Mini Supervisório desenvolvido em plataforma Open Source.

Clique para Ampliar


O supervisório funciona de maneira bem simples, tenho a possibilidade de modificar o SP,  KP, KI, KD , A/M, MV(Se estiver em manual), e um gráfico bem simples, para estudo de comportamento da variável.
 o ScadaBR, tem internamente o BD Derby , isso facilitou em inserir uma pesquisa dos históricos dos 'Datapoints' criado.

Mini Supervisório para controle de luminosidade utilizando o ScadaBR (Supervisorio Open Source) + Arduíno.
 A parte física é composta por:
LED = Elemento final de controle
LDR= Elemento Sensor
Arduíno = Controlador
'agradeço a Neto por me adquirir a maioria dos componentes.'

     A comunicação entre o Arduíno e o ScadaBR é feita através do protocolo modbus, tive que fazer algumas alterações no código que cria a comunicação entre o Arduíno e o Sinótico, também no código que executa  PID (biblioteca utilizada).
 Quebrei a cabeça durante algum tempo até que consegui fazer o ScadaBR escrever diretamente no Arduíno através de vários registradores virtuais que eu criei, isso facilitou muito a minha vida, mais acredito que muitos desses podem torna a conexão um pouco lenta.

Código Logo Abaixo: 
Obs: 'Não reparem a bagunça no código, sou técnico em automação, não sou um exímio programando...ainda  ;D .'


void configure_mb_slave(long baud, char parity, char txenpin);


int update_mb_slave(unsigned char slave, int *regs,
unsigned int regs_size);


/* Modbus RTU common parameters, the Master MUST use the same parameters */
enum {
  MB_SLAVE = 1, /* modbus slave id */
};
/* slave registers example */
int sp, button;
enum {        
  MB_REG0,
  MB_REG1,
  MB_REG2,
  MB_REG3,
  MB_REG4,
  MB_REG5,
  MB_REG6,
  MB_REG7,
  MB_REG8,
  MB_REG9,
  MB_REG10,
  MB_REG11,
  MB_REG12,
  MB_REG13,
  MB_REG14,
  MB_REG15,
  MB_REG16,
  MB_REG17,
  MB_REG18,
  MB_REG19,
  MB_REG20,
  MB_REG21,
  MB_REGS
};
int regs[MB_REGS];


#include
int pv, mv, am;
double Setpoint, Input, Output, kp, ti, td, mv_manu;
PID myPID(&Input, &Output, &Setpoint,kp,ti,td, DIRECT);

void setup()

{
  Serial.begin(9600);
  pv = map(analogRead(0), 0,1023,0,100);
  Input =  pv;
  Setpoint = sp;
  
  myPID.SetMode(AUTOMATIC);
  
  configure_mb_slave(9600, 'n', 0);

}


void loop()
{
  update_mb_slave(MB_SLAVE, regs, MB_REGS);
  regs[MB_REG0]=analogRead(A0);
  regs[MB_REG1]=analogRead(A1);
  regs[MB_REG2]=analogRead(A2);
  regs[MB_REG3]=analogRead(A3);
  regs[MB_REG4]=analogRead(A4);
  regs[MB_REG5]=analogRead(A5);
  regs[MB_REG6]=digitalRead(1);
  regs[MB_REG7]=digitalRead(2);
  regs[MB_REG8]=analogRead(3);
  regs[MB_REG9]=digitalRead(4);
  sp=regs[MB_REG14];
  kp=regs[MB_REG17];
  regs[MB_REG16] = pv;
  ti=regs[MB_REG18];
  td=regs[MB_REG19];
  am=regs[MB_REG20];
  mv_manu = regs[MB_REG21];
  myPID.SetTunings(kp, ti, td);
  Setpoint = sp;
  pv = map(analogRead(0), 0,1023,0,100);
  Input = pv;
  myPID.Compute();
  
  if (am == 0)
{
   analogWrite(3,Output);
  regs[MB_REG15]= Output;
 }

 else

{
analogWrite(3,mv_manu);
regs[MB_REG15]= regs[MB_REG21] ;

  
}
  
  switch ( regs[MB_REG10]) {
  case 1:
    digitalWrite(10,HIGH);
    break;
  case 0:
    digitalWrite(10,LOW);
    break;
  default: 
    digitalWrite(10,LOW);
  }

  switch ( regs[MB_REG11]) {
  case 1:
digitalWrite(11,HIGH);
    break;
  case 0:
    digitalWrite(11,LOW);
    break;
  default: 
    digitalWrite(11,LOW);
  }
  switch ( regs[MB_REG13]) {
  case 1:
    digitalWrite(13,1);
    break;
  case 0:
    digitalWrite(13,0);
    break;
  default: 
    digitalWrite(13,0);
  }
  switch (am) {
  case 1:
   myPID.SetMode(MANUAL);
    break;
  case 0:
    myPID.SetMode(AUTOMATIC);
    break;
  default: 
   myPID.SetMode(MANUAL);
  }
}

/****************************************************************************
 * BEGIN MODBUS RTU SLAVE FUNCTIONS
 ****************************************************************************/


unsigned int Txenpin =9;     /* Enable transmission pin, used on RS485 networks */


/* enum of supported modbus function codes. If you implement a new one, put its function code here ! */
enum { 
  FC_READ_REGS  = 0x03,   //Read contiguous block of holding register
  FC_WRITE_REG  = 0x06,   //Write single holding register
  FC_WRITE_REGS = 0x10    //Write block of contiguous registers
};

/* supported functions. If you implement a new one, put its function code into this array! */
const unsigned char fsupported[] = { 
  FC_READ_REGS, FC_WRITE_REG, FC_WRITE_REGS };

/* constants */
enum { 
  MAX_READ_REGS = 0x7D, 
  MAX_WRITE_REGS = 0x7B, 
  MAX_MESSAGE_LENGTH = 256 
};


enum { 
  RESPONSE_SIZE = 6, 
  EXCEPTION_SIZE = 3, 
  CHECKSUM_SIZE = 2 
};

/* exceptions code */
enum { 
  NO_REPLY = -1, 
  EXC_FUNC_CODE = 1, 
  EXC_ADDR_RANGE = 2, 
  EXC_REGS_QUANT = 3, 
  EXC_EXECUTE = 4 
};

/* positions inside the query/response array */
enum { 
  SLAVE = 0, 
  FUNC, 
  START_H, 
  START_L, 
  REGS_H, 
  REGS_L, 
  BYTE_CNT 
};


/*
CRC

 INPUTS:
  buf   ->  Array containing message to be sent to controller.            
  start ->  Start of loop in crc counter, usually 0.
  cnt   ->  Amount of bytes in message being sent to controller/
 OUTPUTS:
  temp  ->  Returns crc byte for message.
 COMMENTS:
  This routine calculates the crc high and low byte of a message.
  Note that this crc is only used for Modbus, not Modbus+ etc. 
 ****************************************************************************/

unsigned int crc(unsigned char *buf, unsigned char start,
unsigned char cnt) 
{
  unsigned char i, j;
  unsigned temp, temp2, flag;

  temp = 0xFFFF;

  for (i = start; i < cnt; i++) {
    temp = temp ^ buf[i];

    for (j = 1; j <= 8; j++) {
      flag = temp & 0x0001;
      temp = temp >> 1;
      if (flag)
        temp = temp ^ 0xA001;
    }
  }

  /* Reverse byte order. */
  temp2 = temp >> 8;
  temp = (temp << 8) | temp2;
  temp &= 0xFFFF;

  return (temp);
}




/***********************************************************************
 * 
 * The following functions construct the required query into
 * a modbus query packet.
 * 
 ***********************************************************************/

/* 
 * Start of the packet of a read_holding_register response 
 */
void build_read_packet(unsigned char slave, unsigned char function,
unsigned char count, unsigned char *packet) 
{
  packet[SLAVE] = slave;
  packet[FUNC] = function;
  packet[2] = count * 2;

/* 
 * Start of the packet of a preset_multiple_register response 
 */
void build_write_packet(unsigned char slave, unsigned char function,
unsigned int start_addr, 
unsigned char count,
unsigned char *packet) 
{
  packet[SLAVE] = slave;
  packet[FUNC] = function;
  packet[START_H] = start_addr >> 8;
  packet[START_L] = start_addr & 0x00ff;
  packet[REGS_H] = 0x00;
  packet[REGS_L] = count;

/* 
 * Start of the packet of a write_single_register response 
 */
void build_write_single_packet(unsigned char slave, unsigned char function,
unsigned int write_addr, unsigned int reg_val, unsigned char* packet) 
{
  packet[SLAVE] = slave;
  packet[FUNC] = function;
  packet[START_H] = write_addr >> 8;
  packet[START_L] = write_addr & 0x00ff;
  packet[REGS_H] = reg_val >> 8;
  packet[REGS_L] = reg_val & 0x00ff;


/* 
 * Start of the packet of an exception response 
 */
void build_error_packet(unsigned char slave, unsigned char function,
unsigned char exception, unsigned char *packet) 
{
  packet[SLAVE] = slave;
  packet[FUNC] = function + 0x80;
  packet[2] = exception;


/*************************************************************************
 * 
 * modbus_query( packet, length)
 * 
 * Function to add a checksum to the end of a packet.
 * Please note that the packet array must be at least 2 fields longer than
 * string_length.
 **************************************************************************/

void modbus_reply(unsigned char *packet, unsigned char string_length) 
{
  int temp_crc;

  temp_crc = crc(packet, 0, string_length);
  packet[string_length] = temp_crc >> 8;
  string_length++;
  packet[string_length] = temp_crc & 0x00FF;



/***********************************************************************
 * 
 * send_reply( query_string, query_length )
 * 
 * Function to send a reply to a modbus master.
 * Returns: total number of characters sent
 ************************************************************************/

int send_reply(unsigned char *query, unsigned char string_length) 
{
  unsigned char i;

  if (Txenpin > 1) { // set MAX485 to speak mode 
    UCSR0A=UCSR0A |(1 << TXC0);
    digitalWrite( Txenpin, HIGH);
    delay(1);
  }

  modbus_reply(query, string_length);
  string_length += 2;

  for (i = 0; i < string_length; i++) {
   Serial.write(byte(query[i]));
  }

  if (Txenpin > 1) {// set MAX485 to listen mode 
    while (!(UCSR0A & (1 << TXC0)));
    digitalWrite( Txenpin, LOW);
  }

  return i; /* it does not mean that the write was succesful, though */
}

/***********************************************************************
 * 
 * receive_request( array_for_data )
 * 
 * Function to monitor for a request from the modbus master.
 * 
 * Returns: Total number of characters received if OK
 * 0 if there is no request 
 * A negative error code on failure
 ***********************************************************************/

int receive_request(unsigned char *received_string) 
{
  int bytes_received = 0;

  /* FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? */
  while (Serial.available()) {
    received_string[bytes_received] = Serial.read();
    bytes_received++;
    if (bytes_received >= MAX_MESSAGE_LENGTH)
      return NO_REPLY; /* port error */
  }

  return (bytes_received);
}


/*********************************************************************
 * 
 * modbus_request(slave_id, request_data_array)
 * 
 * Function to the correct request is returned and that the checksum
 * is correct.
 * 
 * Returns: string_length if OK
 * 0 if failed
 * Less than 0 for exception errors
 * 
 * Note: All functions used for sending or receiving data via
 *      modbus return these return values.
 * 
 **********************************************************************/

int modbus_request(unsigned char slave, unsigned char *data) 
{
  int response_length;
  unsigned int crc_calc = 0;
  unsigned int crc_received = 0;
  unsigned char recv_crc_hi;
  unsigned char recv_crc_lo;

  response_length = receive_request(data);

  if (response_length > 0) {
    crc_calc = crc(data, 0, response_length - 2);
    recv_crc_hi = (unsigned) data[response_length - 2];
    recv_crc_lo = (unsigned) data[response_length - 1];
    crc_received = data[response_length - 2];
    crc_received = (unsigned) crc_received << 8;
    crc_received =
      crc_received | (unsigned) data[response_length - 1];

    /*********** check CRC of response ************/
    if (crc_calc != crc_received) {
      return NO_REPLY;
    }

    /* check for slave id */
    if (slave != data[SLAVE]) {
      return NO_REPLY;
    }
  }
  return (response_length);
}

/*********************************************************************
 * 
 * validate_request(request_data_array, request_length, available_regs)
 * 
 * Function to check that the request can be processed by the slave.
 * 
 * Returns: 0 if OK
 * A negative exception code on error
 * 
 **********************************************************************/

int validate_request(unsigned char *data, unsigned char length,
unsigned int regs_size) 
{
  int i, fcnt = 0;
  unsigned int regs_num = 0;
  unsigned int start_addr = 0;
  unsigned char max_regs_num;

  /* check function code */
  for (i = 0; i < sizeof(fsupported); i++) {
    if (fsupported[i] == data[FUNC]) {
      fcnt = 1;
      break;
    }
  }
  if (0 == fcnt)
    return EXC_FUNC_CODE;

  if (FC_WRITE_REG == data[FUNC]) {
    /* For function write single reg, this is the target reg.*/
    regs_num = ((int) data[START_H] << 8) + (int) data[START_L];
    if (regs_num >= regs_size)
      return EXC_ADDR_RANGE;
    return 0;
  }

  /* For functions read/write regs, this is the range. */
  regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L];

  /* check quantity of registers */
  if (FC_READ_REGS == data[FUNC])
    max_regs_num = MAX_READ_REGS;
  else if (FC_WRITE_REGS == data[FUNC])
    max_regs_num = MAX_WRITE_REGS;

  if ((regs_num < 1) || (regs_num > max_regs_num))
    return EXC_REGS_QUANT;

  /* check registers range, start address is 0 */
  start_addr = ((int) data[START_H] << 8) + (int) data[START_L];
  if ((start_addr + regs_num) > regs_size)
    return EXC_ADDR_RANGE;

  return 0; /* OK, no exception */
}



/************************************************************************
 * 
 * write_regs(first_register, data_array, registers_array)
 * 
 * writes into the slave's holding registers the data in query, 
 * starting at start_addr.
 * 
 * Returns:   the number of registers written
 ************************************************************************/

int write_regs(unsigned int start_addr, unsigned char *query, int *regs) 
{
  int temp;
  unsigned int i;

  for (i = 0; i < query[REGS_L]; i++) {
    /* shift reg hi_byte to temp */
    temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8;
    /* OR with lo_byte           */
    temp = temp | (int) query[(BYTE_CNT + 2) + i * 2];

    regs[start_addr + i] = temp;
  } 
  return i;
}

/************************************************************************
 * 
 * preset_multiple_registers(slave_id, first_register, number_of_registers,
 * data_array, registers_array)
 * 
 * Write the data from an array into the holding registers of the slave. 
 * 
 *************************************************************************/

int preset_multiple_registers(unsigned char slave,
unsigned int start_addr,
unsigned char count, 
unsigned char *query,
int *regs) 
{
  unsigned char function = FC_WRITE_REGS; /* Preset Multiple Registers */
  int status = 0;
  unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];

  build_write_packet(slave, function, start_addr, count, packet);

  if (write_regs(start_addr, query, regs)) {
    status = send_reply(packet, RESPONSE_SIZE);
  }

  return (status);
}


/************************************************************************
 * 
 * write_single_register(slave_id, write_addr, data_array, registers_array)
 * 
 * Write a single int val into a single holding register of the slave. 
 * 
 *************************************************************************/

int write_single_register(unsigned char slave,
unsigned int write_addr, unsigned char *query, int *regs) 
{
  unsigned char function = FC_WRITE_REG; /* Function: Write Single Register */
  int status = 0;
  unsigned int reg_val;
  unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];

  reg_val = query[REGS_H] << 8 | query[REGS_L];
  build_write_single_packet(slave, function, write_addr, reg_val, packet);
  regs[write_addr] = (int) reg_val;
  /*
        written.start_addr=write_addr;
   written.num_regs=1;
   */
  status = send_reply(packet, RESPONSE_SIZE);    

  return (status);
}


/************************************************************************
 * 
 * read_holding_registers(slave_id, first_register, number_of_registers,
 * registers_array)
 * 
 * reads the slave's holdings registers and sends them to the Modbus master
 * 
 *************************************************************************/

int read_holding_registers(unsigned char slave, unsigned int start_addr,

unsigned char reg_count, int *regs) 
{
  unsigned char function = 0x03; /* Function 03: Read Holding Registers */
  int packet_size = 3;
  int status;
  unsigned int i;
  unsigned char packet[MAX_MESSAGE_LENGTH];

  build_read_packet(slave, function, reg_count, packet);

  for (i = start_addr; i < (start_addr + (unsigned int) reg_count);
      i++) {
      packet[packet_size] = regs[i] >> 8;
    packet_size++;
    packet[packet_size] = regs[i] & 0x00FF;
    packet_size++;
  } 

  status = send_reply(packet, packet_size);

  return (status);
}


void configure_mb_slave(long baud, char parity, char txenpin)
{
  Serial.begin(baud);

  switch (parity) {
  case 'e': // 8E1
    UCSR0C |= ((1<
    //      UCSR0C &= ~((1<
    break;
  case 'o': // 8O1
    UCSR0C |= ((1<
    //      UCSR0C &= ~((1<
    break;
  case 'n': // 8N1
    UCSR0C |= ((1<
    //      UCSR0C &= ~((1<
    break;                
  default:
    break;
  }

  if (txenpin > 1) { // pin 0 & pin 1 are reserved for RX/TX
    Txenpin = txenpin; /* set global variable */
    pinMode(Txenpin, OUTPUT);
    digitalWrite(Txenpin, LOW);
  }

  return;
}   

/*
 * update_mb_slave(slave_id, holding_regs_array, number_of_regs)
 * 
 * checks if there is any valid request from the modbus master. If there is,
 * performs the action requested
 */

unsigned long Nowdt = 0;
unsigned int lastBytesReceived;
const unsigned long T35 = 5;

int update_mb_slave(unsigned char slave, int *regs,
unsigned int regs_size) 
{
  unsigned char query[MAX_MESSAGE_LENGTH];
  unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE];
  unsigned int start_addr;
  int exception;
  int length = Serial.available();
  unsigned long now = millis();

  if (length == 0) {
    lastBytesReceived = 0;
    return 0;
  }

  if (lastBytesReceived != length) {
    lastBytesReceived = length;
    Nowdt = now + T35;
    return 0;
  }
  if (now < Nowdt) 
    return 0;

  lastBytesReceived = 0;

  length = modbus_request(slave, query);
  if (length < 1)
    return length;


  exception = validate_request(query, length, regs_size);
  if (exception) {
    build_error_packet(slave, query[FUNC], exception,
    errpacket);
    send_reply(errpacket, EXCEPTION_SIZE);
    return (exception);
  } 


  start_addr = ((int) query[START_H] << 8) +
    (int) query[START_L];
  switch (query[FUNC]) {
  case FC_READ_REGS:
    return read_holding_registers(slave, 
    start_addr,
    query[REGS_L],
    regs);
    break;
  case FC_WRITE_REGS:
    return preset_multiple_registers(slave,
    start_addr,
    query[REGS_L],
    query,
    regs);
    break;
  case FC_WRITE_REG:
    write_single_register(slave,
    start_addr,
    query,
    regs);
    break;                                
  }
}








Share: