brotherax_teletype/brotherax240_cntrl/src/main.cpp

401 lines
11 KiB
C++

#include "Arduino.h"
bool use_rn=false; //if use_rn=true, CR and LF only do what they say. if use_rn=false \r is ignored and \n does CRLF(=Enter)
//Arduino 1.8.3
//STM32F103C, 64k flash
//upload method: serial (A9 to RX, A10 to TX)
//To upload set Boot0 jumper to 1 (the one further away from reset btn) and press reset (stm will boot from flash wich contains uart to flash uploader)
//To boot program after restart set Boot0 jumper to 0
//#define DEBUG
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
void checkSerial();
bool textAvailable();
bool checkTextbuffer();
void sendChar(char c,char c2);
void coilInterrupt();
//pins die nicht gehn als output:
/* PA15
* PB3
* PB4
* PA12
*/
#if defined(BROTHERAX240)
#define SCAN_0 PA1
#define SCAN_1 PA2
#define SCAN_2 PA3
#define SCAN_3 PA4
#define SCAN_4 PA5
#define SCAN_5 PA6
#define SCAN_6 PA7
#define SCAN_7 PB0
#define SCAN_8 PB1
#define IN_A PB13
#define IN_B PB14
#define IN_C PB15
#define IN_D PB5
#define IN_E PB6
#define IN_F PB7
#define IN_G PB8
#define IN_H PB9
#elif defined(BROTHERAX130)
#define SCAN_0 PA1
#define SCAN_1 PA2
#define SCAN_2 PA3
#define SCAN_3 PA4
#define SCAN_4 PA5
#define SCAN_5 PA6
#define SCAN_6 PA7
#define SCAN_7 PB0
//#define SCAN_8 PB1
#define IN_A PB13
#define IN_B PB14
#define IN_C PB15
#define IN_D PB5
#define IN_E PB6
#define IN_F PB7
#define IN_G PB8
#define IN_H PB9
#endif
#define PIN_LED PC13
#if !defined(PIN_COIL_SENSE)
#define PIN_COIL_SENSE PB11
#endif
#define LEDON LOW
#define LEDOFF HIGH
#if defined(BROTHERAX240)
#define NUM_SCANPINS 9
int scanaddress[]={SCAN_0,SCAN_1,SCAN_2,SCAN_3,SCAN_4,SCAN_5,SCAN_6,SCAN_7,SCAN_8};
#define NUM_INADDR 8
int inaddress[]={IN_A,IN_B,IN_C,IN_D,IN_E,IN_F,IN_G,IN_H};
#include "matrix_ax240.h"
#elif defined(BROTHERAX130)
#define NUM_SCANPINS 8
int scanaddress[]={SCAN_0,SCAN_1,SCAN_2,SCAN_3,SCAN_4,SCAN_5,SCAN_6,SCAN_7};
#define NUM_INADDR 8
int inaddress[]={IN_A,IN_B,IN_C,IN_D,IN_E,IN_F,IN_G,IN_H};
#include "matrix_ax130.h"
#endif
#define TEXTBUFFERSIZE 8192
byte textbuffer[TEXTBUFFERSIZE]; //ca 60-65 Zeilen pro DinA4, a 65 characters (10 Pica), 78 characters (12 Elite) or 97 characters (15 Mikron)
uint16_t bufferpos_write=0;
uint16_t bufferpos_read=0;
#define DELAY_KEYPRESS 100 //delay in ms between keypresses
long last_keypress=0;
bool linefeed_used=false; //if Linefeed key was used CR (CODE+Enter) must be pressed twice for full CR
volatile uint16_t count_bufferedchars=0; //keeps track of buffered characters on the typewriter
#define MAX_TYPEWRITER_BUFFERCOUNT 2
#define MAXIMUM_COILWAIT 5000 //if no interrupt from coil received decrease buffer count after this time (in ms)
void setup() {
if (use_rn) { //change matrix mapping if CR and LF are used
#if defined(BROTHERAX240)
byte _km10[NUM_SCANPINS]={0,0,16,0,0,0,0,0,0}; //10 = [LINE FEED]
byte _km13[NUM_SCANPINS]={0,36,0,0,0,0,0,0,0}; //13 = [CARRIAGE RETURN]
#elif defined(BROTHERAX130)
byte _km10[NUM_SCANPINS]={0,64,0,0,0,0,0,0}; //10 = [LINE FEED]
byte _km13[NUM_SCANPINS]={0,0,0,0,0,0,0,0}; //13 = [CARRIAGE RETURN]
#endif
for (uint8_t i=0;i<NUM_SCANPINS;i++){ //copy array content
keymatrix[10][i]=_km10[i];
keymatrix[13][i]=_km13[i];
}
}
Serial1.begin(9600);
#if defined(BROTHERAX240)
pinMode(SCAN_0,INPUT_PULLUP);
pinMode(SCAN_1,INPUT_PULLUP);
pinMode(SCAN_2,INPUT_PULLUP);
pinMode(SCAN_3,INPUT_PULLUP);
pinMode(SCAN_4,INPUT_PULLUP);
pinMode(SCAN_5,INPUT_PULLUP);
pinMode(SCAN_6,INPUT_PULLUP);
pinMode(SCAN_7,INPUT_PULLUP);
pinMode(SCAN_8,INPUT_PULLUP);
pinMode(IN_A,OUTPUT);
pinMode(IN_B,OUTPUT);
pinMode(IN_C,OUTPUT);
pinMode(IN_D,OUTPUT);
pinMode(IN_E,OUTPUT);
pinMode(IN_F,OUTPUT);
pinMode(IN_G,OUTPUT);
pinMode(IN_H,OUTPUT);
digitalWrite(IN_A,LOW);
digitalWrite(IN_B,LOW);
digitalWrite(IN_C,LOW);
digitalWrite(IN_D,LOW);
digitalWrite(IN_E,LOW);
digitalWrite(IN_F,LOW);
digitalWrite(IN_G,LOW);
digitalWrite(IN_H,LOW);
#elif defined(BROTHERAX130)
pinMode(SCAN_0,INPUT_PULLUP);
pinMode(SCAN_1,INPUT_PULLUP);
pinMode(SCAN_2,INPUT_PULLUP);
pinMode(SCAN_3,INPUT_PULLUP);
pinMode(SCAN_4,INPUT_PULLUP);
pinMode(SCAN_5,INPUT_PULLUP);
pinMode(SCAN_6,INPUT_PULLUP);
pinMode(SCAN_7,INPUT_PULLUP);
//pinMode(SCAN_8,INPUT_PULLUP);
pinMode(IN_A,OUTPUT);
pinMode(IN_B,OUTPUT);
pinMode(IN_C,OUTPUT);
pinMode(IN_D,OUTPUT);
pinMode(IN_E,OUTPUT);
pinMode(IN_F,OUTPUT);
pinMode(IN_G,OUTPUT);
pinMode(IN_H,OUTPUT);
digitalWrite(IN_A,LOW);
digitalWrite(IN_B,LOW);
digitalWrite(IN_C,LOW);
digitalWrite(IN_D,LOW);
digitalWrite(IN_E,LOW);
digitalWrite(IN_F,LOW);
digitalWrite(IN_G,LOW);
digitalWrite(IN_H,LOW);
#endif
pinMode(PIN_COIL_SENSE, INPUT_PULLUP);
attachInterrupt(PIN_COIL_SENSE, coilInterrupt, RISING); //pin pulled low if coil powered
pinMode(PIN_LED,OUTPUT);
digitalWrite(PIN_LED,LEDON);
delay(500);
digitalWrite(PIN_LED,LEDOFF);
Serial1.println("Brother AX Serialmod");
}
void loop() {
checkSerial(); //check serial buffer and write to textbuffer
if (millis()>last_keypress+DELAY_KEYPRESS){
if (count_bufferedchars<MAX_TYPEWRITER_BUFFERCOUNT) //wait if too many chars are send to typewriter buffer
{
bool charsend=checkTextbuffer(); //check one character from serial buffer and send to typewriter
//Serial1.print(6); //Send ACK
if (charsend){ //a character was actually sent
last_keypress=millis();
}
}
if (count_bufferedchars>0 && millis()>last_keypress+MAXIMUM_COILWAIT){ //coil response timeout
count_bufferedchars--; //decrease buffer count
last_keypress=millis();
}
}
if (count_bufferedchars>=MAX_TYPEWRITER_BUFFERCOUNT){
digitalWrite(PIN_LED,LEDON); //led on -> wait for buffer to empty
}else{
digitalWrite(PIN_LED,LEDOFF); //led off -> buffer isnt full
}
}
void checkSerial(){
while(Serial1.available()){
if (Serial1.available()>0){
char c=Serial1.read();
bufferpos_write++;
bufferpos_write%=TEXTBUFFERSIZE;
textbuffer[bufferpos_write]=c; //bufferpos_write points to last written char position
if (use_rn) {
if (c==10 || (c==13 && linefeed_used)) {
//char 10 is LineFeed. If emulated by pressing 2,4 (arrow down, top right of keyboard), key needs to be pressed twice to get one line spacing
//Also CR (CODE+Enter) must be pressed twice, if LineFeed key is used in the same Text Line
bufferpos_write++;
bufferpos_write%=TEXTBUFFERSIZE;
textbuffer[bufferpos_write]=c; //bufferpos_write points to last written char position
}
if (c==13) {
linefeed_used=false;
}else if(c==10){
linefeed_used=true;
}
}
}
}
}
bool textAvailable(){
if (bufferpos_write!=bufferpos_read){
return true;
}
return false;
}
bool checkTextbuffer(){
bool returnvalue=false;
//while(Serial1.available()){
//if (Serial1.available()>0){
if (textAvailable()) { //buffer contains unread chars
bufferpos_read++;//bufferpos_read points to last read char position
bufferpos_read%=TEXTBUFFERSIZE;
char c = textbuffer[bufferpos_read];
#ifdef DEBUG
Serial1.print((uint8_t)c); //echo
Serial1.print("="); //echo
Serial1.println(c); //echo
#endif
if (c==195 || c==194) { //umlaut
#ifdef DEBUG
Serial1.print("Uml:");
#endif
while (!textAvailable()){ checkSerial(); } //wait for next byte and checkSerial in between
bufferpos_read++;//bufferpos_read points to last read char position
bufferpos_read%=TEXTBUFFERSIZE;
char c2=textbuffer[bufferpos_read];
#ifdef DEBUG
Serial1.println((uint8_t)c2); //echo
#endif
sendChar(c,c2); //2 byte character
returnvalue=true;
}else{
sendChar(c,0); //normal 1 byte character
returnvalue=true;
}
}
//}
return returnvalue; //true= character send, false=buffer was empty
}
void sendChar(char c,char c2) { //c2 =0 for 1 byte characters
uint8_t keypress[NUM_SCANPINS]={0}; //keypress contains id of input pin. 0=not pressed, A=2^0, B=2^1, C=2^3 ...
//check if key is implemented (not all 255,255,255,..)
bool keyimplemented=false;
for (uint8_t i=0;i<NUM_SCANPINS;i++){
if (keymatrix[c][i]!=0){
keyimplemented=true;
}
}
if (keyimplemented && ( (c>=32 && c<127) || c==10 || c==13 ) ) { //1 byte char
#ifdef DEBUG
Serial1.println("1 byte char");
#endif
for (uint8_t i=0;i<NUM_SCANPINS;i++){
keypress[i]=keymatrix[c][i]; //copy keypress connections for current char
}
}else if (c==195){ //umlauts
#ifdef DEBUG
Serial1.println("2 byte char");
#endif
for (uint8_t i=0;i<NUM_SCANPINS;i++){
keypress[i]=keymatrix195[c2][i]; //copy keypress connections for current char
}
}else if(c==194){ //others
if (c2==167){ // §
keypress[0]=128; keypress[7]=16; //shift + 3
}else if (c2==176){ // °
keypress[1]=32; keypress[3]=8; //CODE + W
}
}else if(c>=32){ //not recognized character (everything else) and not a control command
keypress[1]=128; // [SPACE] //print space to keep text aligned
}
//Update count buffered chars
if ((c>32 && c<127) ) { //pressed key uses hammer. (32 is space)
if (keyimplemented){ //keymatrix was implemented for c (not 255,255...)
count_bufferedchars++; //character send to typewriter. Increase character buffer count
}
}
//digitalWrite(PIN_LED,LEDON);
#define HOLDCYCLES 3
for (uint8_t hold=0;hold<HOLDCYCLES;hold++){ //cycles to hold the key
for (uint8_t i=0;i<NUM_SCANPINS;i++){
if (keypress[i]!=0){ //some key on scan i will be pressed
unsigned int scanaddr=scanaddress[i]; //get pin address for i SCAN_i
uint8_t keypresses=keypress[i];
while(digitalRead(scanaddr)){ }//wait while high
for (int b=0;b<NUM_INADDR;b++) { //set inaddress outputs to 1 bits from keypresses. Example: if keypresses=129, inaddress[0] and inaddress[7] will be used
if (CHECK_BIT(keypresses,b)) {
digitalWrite(inaddress[b],HIGH);
}
}
while(!digitalRead(scanaddr)){ } //wait while low
for (int b=0;b<NUM_INADDR;b++) { //set inaddress outputs to 1 bits from keypresses. Example: if keypresses=129, inaddress[0] and inaddress[7] will be used
if (CHECK_BIT(keypresses,b)) {
digitalWrite(inaddress[b],LOW); //set high -> transistor pulls input of printer to ground
}
}
}
}
}
//digitalWrite(PIN_LED,LEDOFF);
}
void coilInterrupt(){
if (count_bufferedchars>0){
count_bufferedchars--;
}
}