├── utils.c ├── utils.h ├── README ├── uart.h ├── common.h ├── cmdrecv.h ├── mdb_uart.h ├── main.c ├── uart.c ├── mdb_uart.c ├── mdb_billv.h ├── mdb.h ├── mdb.c ├── cmdrecv.c ├── Makefile └── mdb_billv.c /utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | 4 | unsigned short conv_order_short(unsigned short i) 5 | { 6 | return (i<<8) | (i>>8); 7 | } 8 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H 2 | #define _UTILS_H 3 | 4 | 5 | unsigned short conv_order_short(unsigned short i); 6 | 7 | 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | MDB/ICP is a standard used for the perpherals of vending machine, like Coin Acceptor/Changer or Bill Validator/Recycler, etc. 2 | 3 | In fact, MDB is just a 9600bps UART but in 9bit mode, so you can't connect it to PC directly. 4 | 5 | 6 | The code running in a AVR mcu, it preprocess some low level MDB protocol, and give you other UART to PC, you can control it easily then. 7 | 8 | -------------------------------------------------------------------------------- /uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _UART_H 2 | #define _UART_H 1 3 | 4 | #define RawQueueSize 64 5 | typedef struct 6 | { 7 | char queue[RawQueueSize]; 8 | unsigned char in; 9 | unsigned char out; 10 | unsigned char counter; 11 | } _raw_queue; 12 | static volatile _raw_queue raw_queue; 13 | 14 | 15 | void _putc(char); 16 | void uart_print(unsigned char *); 17 | void uart_init(void); 18 | signed char uart_dequeue(void); 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h include all common header file 3 | */ 4 | 5 | #ifndef _COMMON_H 6 | #define _COMMON_H 1 7 | 8 | 9 | #define F_CPU 14745600 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #endif 23 | /* .end of the filey */ 24 | -------------------------------------------------------------------------------- /cmdrecv.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _CMDRECV_H 3 | #define _CMDRECV_H 4 | 5 | #define STX '<' 6 | #define ETX '>' 7 | #define IN_PACKET 1 8 | #define OUT_PACKET 0 9 | 10 | #define BUFFMAX 64 11 | 12 | 13 | struct _p_list 14 | { 15 | char *para; 16 | struct _p_list *next; 17 | }; 18 | typedef struct _p_list p_list; 19 | 20 | 21 | void cmdrecv_p_list_clear(p_list *head); 22 | void cmdrecv_process(char *p_buf); 23 | void cmdrecv_uart_tick(void); 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /mdb_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef _MDB_UART_H 2 | #define _MDB_UART_H 1 3 | 4 | #define MDB_RX_MAX 96 5 | typedef struct 6 | { 7 | unsigned short queue[MDB_RX_MAX]; 8 | unsigned char in; 9 | unsigned char out; 10 | unsigned char count; 11 | 12 | } _mdb_queue; 13 | volatile _mdb_queue mdb_rx; 14 | 15 | #define IN_PACKET 1 16 | #define OUT_PACKET 0 17 | 18 | void mdb_uart_init(void); 19 | void mdb_uart_putc(char mode, char data); 20 | void mdb_uart_flush(void); 21 | void mdb_uart_send(unsigned short *buf, unsigned char length); 22 | signed short mdb_uart_deq(void); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: chopin1998@gmail.com 3 | */ 4 | 5 | 6 | #include "common.h" 7 | #include "mdb.h" 8 | 9 | void init_uart(void); 10 | void init_io(void); 11 | void killdog(void); 12 | 13 | uint8_t mcusr_mirror __attribute__((section (".noinit"))); 14 | void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3"))); 15 | 16 | 17 | int main() 18 | { 19 | unsigned int i=0; 20 | 21 | killdog(); 22 | 23 | init_io(); 24 | uart_init(); 25 | mdb_uart_init(); 26 | 27 | mdb_init(); 28 | mdb_billv_init(); 29 | 30 | sei(); 31 | 32 | for(;;) 33 | { 34 | // mdb_timer_set(500); 35 | // while (!mdb_timer_is_shot()); 36 | 37 | cmdrecv_uart_tick(); 38 | 39 | mdb_polling(); 40 | 41 | _delay_ms(250); 42 | } 43 | 44 | cli(); 45 | wdt_enable(WDTO_500MS); /* should not run here */ 46 | for(;;); 47 | } 48 | 49 | void init_io() 50 | { 51 | /* 52 | * PORTA 53 | * all pins used as ADC input channel 54 | */ 55 | DDRA = 0x00; 56 | PORTA = 0x00; 57 | 58 | /* 59 | * PORTB 60 | */ 61 | DDRB = 0xff; 62 | PORTB = 0xff; 63 | 64 | /* 65 | * PORTC 66 | */ 67 | DDRC = 0x00; 68 | PORTC = 0xff; 69 | 70 | /* 71 | * PORTD 72 | */ 73 | DDRD = 0xfa; 74 | PORTD = 0xff; 75 | } 76 | 77 | void killdog(void) 78 | { 79 | mcusr_mirror = MCUSR; 80 | MCUSR = 0; 81 | wdt_disable(); 82 | } 83 | -------------------------------------------------------------------------------- /uart.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "uart.h" 3 | 4 | 5 | void uart_init() 6 | { 7 | UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); 8 | UBRR0H = 0; 9 | UBRR0L = 15; /* 57600 @ 14745600hz */ 10 | 11 | raw_queue.in = 0; 12 | raw_queue.out = 0; 13 | raw_queue.counter = 0; 14 | } 15 | 16 | void uart_print(unsigned char *buf) 17 | { 18 | unsigned int len = strlen(buf); 19 | 20 | if (len > 0) 21 | { 22 | for (int i=0; i= RawQueueSize) 61 | { // queue full !! extreme dangerous 62 | raw_queue.queue[0] = recv; 63 | raw_queue.in = 1; 64 | raw_queue.out = 0; 65 | raw_queue.counter = 1; 66 | } 67 | else 68 | { // enqueue normally 69 | raw_queue.queue[raw_queue.in] = recv; 70 | raw_queue.in = (raw_queue.in + 1) % RawQueueSize; 71 | raw_queue.counter++; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /mdb_uart.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "mdb_uart.h" 3 | 4 | void mdb_uart_init() 5 | { 6 | UCSR1B = _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1); 7 | UBRR1H = 0; 8 | UBRR1L = 95; /* 9600bps @ 14745600Hz */ 9 | 10 | UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10); /* 9bit mode */ 11 | UCSR1B |= _BV(UCSZ12); /* 9bit mode */ 12 | 13 | //////////////// 14 | //////////////// 15 | mdb_rx.in = 0; 16 | mdb_rx.out = 0; 17 | mdb_rx.count = 0; 18 | } 19 | 20 | void mdb_uart_send(unsigned short *buf, unsigned char length) 21 | { 22 | for (unsigned char i=0; i> 8, buf[i]); 25 | } 26 | } 27 | 28 | void mdb_uart_flush() 29 | { 30 | // mdb_uart_init(); 31 | 32 | mdb_rx.in = 0; 33 | mdb_rx.out = 0; 34 | mdb_rx.count = 0; 35 | } 36 | 37 | void mdb_uart_putc(char mode, char data) 38 | { 39 | loop_until_bit_is_set(UCSR1A, UDRE1); 40 | 41 | if (mode) { 42 | UCSR1B |= _BV(TXB81); 43 | } else { 44 | UCSR1B &= ~_BV(TXB81); 45 | } 46 | 47 | UDR1 = data; 48 | } 49 | 50 | /* 51 | * return -1, means no data in queue 52 | * otherwise, means a data 53 | */ 54 | signed short mdb_uart_deq() 55 | { 56 | unsigned short rev; 57 | 58 | if (mdb_rx.count == 0) { 59 | rev = -1; /* -1 means no data in queue */ 60 | } else { 61 | rev = mdb_rx.queue[mdb_rx.out]; 62 | mdb_rx.out = (mdb_rx.out + 1) % MDB_RX_MAX; 63 | mdb_rx.count--; 64 | } 65 | 66 | return rev; 67 | } 68 | 69 | ISR(USART1_RX_vect) 70 | { 71 | static unsigned char mode; 72 | static unsigned short data; 73 | 74 | mode = (UCSR1B & _BV(RXB81)) >> RXB81; 75 | data = (mode << 8) | UDR1; 76 | 77 | if (mdb_rx.count >= MDB_RX_MAX) { /* queue full! */ 78 | mdb_rx.queue[0] = data; 79 | mdb_rx.in = 1; 80 | mdb_rx.out = 0; 81 | mdb_rx.count = 1; 82 | } else { /* enqueue normally */ 83 | mdb_rx.queue[mdb_rx.in] = data; 84 | mdb_rx.in = (mdb_rx.in + 1) % MDB_RX_MAX; 85 | mdb_rx.count++; 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /mdb_billv.h: -------------------------------------------------------------------------------- 1 | #ifndef _MDB_BILLV_H 2 | #define _MBD_BILLV_H 3 | 4 | 5 | #define MDB_BILLV_POLL_STATUS_DEFECTIVE_MOTOR 0x01 6 | #define MDB_BILLV_POLL_STATUS_SENSOR_PROBLEM 0x02 7 | #define MDB_BILLV_POLL_STATUS_BUSY 0x03 8 | #define MDB_BILLV_POLL_STATUS_ROM_ERROR 0x04 9 | #define MDB_BILLV_POLL_STATUS_JAMMED 0x05 10 | #define MDB_BILLV_POLL_STATUS_JUST_RESET 0x06 11 | #define MDB_BILLV_POLL_STATUS_BILL_REMOVED 0x07 12 | #define MDB_BILLV_POLL_STATUS_NO_CASHBOX 0x08 13 | #define MDB_BILLV_POLL_STATUS_DISABLED 0x09 14 | #define MDB_BILLV_POLL_STATUS_INVALID_ESCROW 0x0a 15 | #define MDB_BILLV_POLL_STATUS_BILL_REJECTED 0x0b 16 | #define MDB_BILLV_POLL_STATUS_STACKED_REMOVE 0x0c 17 | #define MDB_BILLV_POLL_STATUS_INVALID_TYIES_BASE 0x40 18 | 19 | #define MDB_BILLV_ACCEPT_STATUS_STACKED 0x00 20 | #define MDB_BILLV_ACCEPT_STATUS_ESCROW 0x01 21 | #define MDB_BILLV_ACCEPT_STATUS_RETURNED 0x02 22 | #define MDB_BILLV_ACCEPT_STATUS_TO_RECYCLER 0x03 23 | #define MDB_BILLV_ACCEPT_STATUS_DISABLED 0x04 24 | #define MDB_BILLV_ACCEPT_STATUS_MANUAL_FILL 0x05 25 | #define MDB_BILLV_ACCEPT_STATUS_MANUAL_DISPENSE 0x06 26 | #define MDB_BILLV_ACCEPT_STATUS_TO_CASHBOX 0x07 27 | 28 | 29 | typedef struct 30 | { 31 | unsigned char poll_info[64]; 32 | } _billv_device_info; 33 | _billv_device_info mdb_billv_dev_info; 34 | 35 | typedef struct 36 | { 37 | unsigned char level; 38 | unsigned short country; 39 | unsigned short scaling_factor; 40 | unsigned char decimal_place; 41 | unsigned short stacker_capacity; 42 | unsigned short security_level; 43 | unsigned char escrow; 44 | unsigned char type[16]; 45 | } _mdb_setup_info; 46 | _mdb_setup_info mdb_setup_info; 47 | 48 | 49 | 50 | void mdb_billv_init(void); 51 | 52 | void mdb_billv_handler(void); 53 | 54 | unsigned char mdb_billv_parse_setupinfo(unsigned char *buf, 55 | unsigned char len); 56 | 57 | void mdb_billv_enable(void); 58 | void mdb_billv_disable(void); 59 | void mdb_billv_escrow(unsigned char statck); 60 | void mdb_billv_stacker_info(void); 61 | void mdb_billv_info(void); 62 | 63 | void mdb_billv_status(void); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /mdb.h: -------------------------------------------------------------------------------- 1 | #ifndef _MDB_H 2 | #define _MDB_H 3 | 4 | /* MDB protocol block limit */ 5 | #define MDB_BLOCK_LIMIT 36 6 | 7 | /* MDB protocol bytes */ 8 | #define MDB_RESP_ACK 0x00 /* acknowledgemnt/ chksum correct */ 9 | #define MDB_RESP_RET 0xaa /* retransmit the last sent data */ 10 | #define MDB_RESP_NAK 0xff /* use silent 5ms instead */ 11 | 12 | /* MDB protocol address assignment */ 13 | #define MDB_ADDR_VMC 0x00 /* reserved for vmc-self */ 14 | #define MDB_ADDR_CHANGER 0x08 15 | #define MDB_ADDR_CASHLESS_1 0x10 /* cashless device #1 */ 16 | #define MDB_ADDR_COM_GW 0x18 17 | #define MDB_ADDR_DISP 0x20 18 | #define MDB_ADDR_EMS 0x28 /* energy management system */ 19 | #define MDB_ADDR_BILLV 0x30 /* bill validator */ 20 | // #define MDB_ADDR_RESERVED 0x38 21 | #define MDB_ADDR_USD_1 0x40 /* universal satellite device #1 */ 22 | #define MDB_ADDR_USD_2 0x48 23 | #define MDB_ADDR_USD_3 0x50 24 | #define MDB_ADDR_COINH_1 0x58 /* coin hopper or tube dispenser 1 */ 25 | #define MDB_ADDR_CASHLESS_2 0x60 /* cashless device #2 */ 26 | #define MDB_ADDR_COINH_2 0x68 /* coin hopper or tube dispenser 2 */ 27 | // a MDB reserved address holl 28 | #define MDB_ADDR_EXPERI_1 0xe0 /* experimental peripheral #1 */ 29 | #define MDB_ADDR_EXPERI_2 0xe8 /* experimental peripheral #2 */ 30 | #define MDB_ADDR_VMSP_1 0xf0 /* vending machine specific peripheral #1 */ 31 | #define MDB_ADDR_VMSP_2 0xf8 /* vending machine specific peripheral #2 */ 32 | 33 | /* MDB protocol, Bill Validators standard command */ 34 | #define MDB_CMD_BILLV_RESET 0x00 35 | #define MDB_CMD_BILLV_SETUP 0x01 36 | #define MDB_CMD_BILLV_SECUR 0x02 37 | #define MDB_CMD_BILLV_POLL 0x03 38 | #define MDB_CMD_BILLV_TYPE 0x04 39 | #define MDB_CMD_BILLV_ESCROW 0x05 40 | #define MDB_CMD_BILLV_STACKER 0x06 41 | #define MDB_CMD_BILLV_EXPCMD 0x07 42 | 43 | 44 | 45 | /* 46 | * MDB state machine 47 | */ 48 | enum {SM_IDLE,}; 49 | 50 | typedef struct 51 | { 52 | unsigned char state; 53 | } _mdb_sm; 54 | volatile _mdb_sm mdb_sm; 55 | 56 | typedef struct 57 | { 58 | unsigned int down_count; 59 | unsigned char shot; 60 | 61 | } _mdb_timer; 62 | volatile _mdb_timer mdb_timer; 63 | 64 | 65 | void mdb_timer_set(unsigned int); 66 | unsigned char mdb_timer_is_shot(void); 67 | 68 | void mdb_init(void); 69 | 70 | enum {MDB_TICK_OK, MDB_TICK_TIMEOUT, MDB_TICK_CHKSUM_ERROR, MDB_TICK_OVERLEN}; 71 | char mdb_tick(unsigned char *buf, unsigned char *length, unsigned int timeout); 72 | 73 | 74 | void mdb_debug_data(unsigned char *buf, unsigned char len); 75 | void mdb_ack(void); 76 | void mdb_send(unsigned char addr, unsigned char cmd, 77 | unsigned char *buf, unsigned char len); 78 | 79 | void mdb_polling(void); 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /mdb.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #include "mdb.h" 4 | #include "mdb_uart.h" 5 | 6 | #include "uart.h" 7 | 8 | 9 | ISR(TIMER0_COMPA_vect) 10 | { 11 | if (mdb_timer.down_count <= 1) { 12 | mdb_timer.shot = 1; 13 | } 14 | 15 | mdb_timer.down_count--; 16 | } 17 | 18 | /* 19 | * used as fixed freq timer 20 | * worked @ 200Hz, CTC mode 21 | */ 22 | void mdb_timer_init() 23 | { 24 | TCCR0A = _BV(WGM01); /* ctc mode */ 25 | TCCR0B = _BV(CS02) | _BV(CS00); /* 1024 preClock */ 26 | 27 | OCR0A = 72 - 1; /* 200Hz */ 28 | 29 | TIMSK0 = _BV(OCIE0A); /* enable irq */ 30 | } 31 | 32 | void mdb_timer_set(unsigned int val) 33 | { 34 | mdb_timer.down_count = (val / 5) ? (val / 5) : 1; 35 | mdb_timer.shot = 0; 36 | } 37 | 38 | unsigned char mdb_timer_is_shot() 39 | { 40 | if (mdb_timer.shot) { 41 | mdb_timer.shot = 0; 42 | return 1; 43 | } else { 44 | return 0; 45 | } 46 | } 47 | 48 | void mdb_init() 49 | { 50 | //////////////// mdb utils 51 | // mdb_timer_init(); 52 | 53 | //////////////// mdb interval structs 54 | } 55 | 56 | char mdb_tick(unsigned char *buf, unsigned char *length, unsigned int timeout) 57 | { 58 | char rev=MDB_TICK_OK; 59 | signed short ch; 60 | unsigned char chksum = 0; 61 | unsigned int timeout_count=0; 62 | unsigned char len = 0; 63 | 64 | memset(buf, 0x00, *length); 65 | for (len=0;;) 66 | { 67 | cli(); 68 | ch = mdb_uart_deq(); 69 | sei(); 70 | 71 | if (ch == -1) { 72 | timeout_count++; 73 | 74 | if (timeout_count > timeout) { 75 | rev = MDB_TICK_TIMEOUT; 76 | break; 77 | } 78 | _delay_us(1); 79 | 80 | } else { 81 | /* debug output */ 82 | 83 | timeout_count = 0; 84 | buf[len] = ch; 85 | len++; 86 | 87 | if (ch & 0x100) { /* last byte detected, checking sum */ 88 | 89 | if (len == 1) { 90 | rev = MDB_TICK_OK; 91 | break; 92 | } else { 93 | 94 | if ((ch&0xff) != chksum) { 95 | rev = MDB_TICK_CHKSUM_ERROR; 96 | break; 97 | } else { 98 | len--; 99 | buf[len] = '\x00'; 100 | rev = MDB_TICK_OK; 101 | break; 102 | } 103 | } 104 | } else { 105 | // if (len > MDB_BLOCK_LIMIT || len > *length) { 106 | if (len > MDB_BLOCK_LIMIT) { 107 | rev = MDB_TICK_OVERLEN; 108 | break; 109 | } 110 | chksum += ch; 111 | } 112 | } 113 | } 114 | 115 | *length = len; 116 | return rev; 117 | } 118 | 119 | void mdb_ack(void) 120 | { 121 | mdb_uart_putc(0, MDB_RESP_ACK); 122 | } 123 | 124 | void mdb_debug_data(unsigned char *buf, unsigned char len) 125 | { 126 | unsigned char tmp[16]; 127 | 128 | uart_print("dump --> "); 129 | for(unsigned char i=0; i= BUFFMAX) 61 | { // a huge packet 62 | packet_state = OUT_PACKET; 63 | memset(cmd_buf, 0x0, BUFFMAX); 64 | cmd_index = 0; 65 | return; 66 | } 67 | } 68 | } 69 | } 70 | 71 | } 72 | } 73 | 74 | 75 | void cmdrecv_p_list_clear(p_list *head) 76 | { 77 | p_list *curr, *tmp; 78 | 79 | curr = head; 80 | while (curr) 81 | { 82 | tmp = curr->next; 83 | free(curr); 84 | curr = tmp; 85 | } 86 | } 87 | 88 | void cmdrecv_process(char *p_buf) 89 | { 90 | // printf("process: %s, length: %d\n", p_buf, strlen(p_buf)); 91 | 92 | p_list *para_head, *curr; 93 | char *p; 94 | unsigned int p_counter = 0; 95 | unsigned int p1, p2, p3; 96 | int rev; 97 | para_head = (p_list *)malloc(sizeof(p_list)); 98 | 99 | unsigned char buf[32]; 100 | 101 | /* splitting */ 102 | p = strtok(p_buf, ","); 103 | curr = para_head; 104 | while (p) 105 | { 106 | p_counter++; 107 | 108 | curr->para = p; 109 | curr->next = (p_list *)malloc(sizeof(p_list)); 110 | curr = curr->next; 111 | 112 | p = strtok(NULL, ","); 113 | } 114 | curr->next = NULL; 115 | 116 | /* processing */ 117 | // printf("number of p: %d\n", p_counter); 118 | 119 | if (!strcmp(para_head->para, "billv")) 120 | { 121 | if (!strcmp(para_head->para, "poll")) 122 | { 123 | // uart_print("poll\n"); 124 | } 125 | else if (!strcmp(para_head->next->para, "enable")) 126 | { 127 | uart_print("billv enable\n"); 128 | mdb_billv_enable(); 129 | } 130 | else if (!strcmp(para_head->next->para, "disable")) 131 | { 132 | uart_print("billv disable\n"); 133 | mdb_billv_disable(); 134 | } 135 | else if (!strcmp(para_head->next->para, "escrow")) 136 | { 137 | if (!strcmp(para_head->next->next->para, "in")) 138 | { 139 | mdb_billv_escrow(1); 140 | } 141 | else 142 | { 143 | mdb_billv_escrow(0); 144 | } 145 | } 146 | else if (!strcmp(para_head->next->para, "stacker")) 147 | { 148 | mdb_billv_stacker_info(); 149 | } 150 | else if (!strcmp(para_head->next->para, "info")) 151 | { 152 | mdb_billv_info(); 153 | } 154 | } 155 | else 156 | { 157 | uart_print("unimplement function\n"); 158 | } 159 | 160 | cmdrecv_p_list_clear(para_head); 161 | } 162 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Hey Emacs, this is a -*- makefile -*- 2 | 3 | # AVR-GCC Makefile template, derived from the WinAVR template (which 4 | # is public domain), believed to be neutral to any flavor of "make" 5 | # (GNU make, BSD make, SysV make) 6 | 7 | 8 | MCU = atmega324p 9 | FORMAT = ihex 10 | TARGET = main 11 | SRC = main.c mdb_uart.c mdb.c mdb_billv.c cmdrecv.c uart.c utils.c 12 | ASRC = 13 | OPT = s 14 | 15 | # Name of this Makefile (used for "make depend"). 16 | MAKEFILE = Makefile 17 | 18 | # Debugging format. 19 | # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. 20 | # AVR (extended) COFF requires stabs, plus an avr-objcopy run. 21 | DEBUG = stabs 22 | 23 | # Compiler flag to set the C Standard level. 24 | # c89 - "ANSI" C 25 | # gnu89 - c89 plus GCC extensions 26 | # c99 - ISO C99 standard (not yet fully implemented) 27 | # gnu99 - c99 plus GCC extensions 28 | CSTANDARD = -std=gnu99 29 | 30 | # Place -D or -U options here 31 | CDEFS = 32 | #CDEFS += -DREMOVE_FLASH_BYTE_SUPPORT 33 | #CDEFS += -DREMOVE_EEPROM_BYTE_SUPPORT 34 | #CDEFS += -DREMOVE_FUSE_AND_LOCK_BIT_SUPPORT 35 | #CDEFS += -DREMOVE_AVRPROG_SUPPORT 36 | #CDEFS += -DREMOVE_BLOCK_SUPPORT 37 | 38 | # Place -I options here 39 | CINCS = 40 | 41 | 42 | CDEBUG = -g$(DEBUG) 43 | CWARN = -Wall -Wstrict-prototypes -Wno-char-subscripts 44 | CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums 45 | #CEXTRA = -Wa,-adhlns=$(<:.c=.lst) 46 | CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CTUNING) $(CEXTRA) 47 | 48 | 49 | #ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs 50 | 51 | 52 | #Additional libraries. 53 | 54 | # Minimalistic printf version 55 | PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min 56 | 57 | # Floating point printf version (requires MATH_LIB = -lm below) 58 | PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt 59 | 60 | PRINTF_LIB = $(PRINTF_LIB_FLOAT) 61 | 62 | # Minimalistic scanf version 63 | SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min 64 | 65 | # Floating point + %[ scanf version (requires MATH_LIB = -lm below) 66 | SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt 67 | 68 | SCANF_LIB = 69 | 70 | MATH_LIB = -lm 71 | 72 | # External memory options 73 | 74 | # 64 KB of external RAM, starting after internal RAM (ATmega128!), 75 | # used for variables (.data/.bss) and heap (malloc()). 76 | #EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff 77 | 78 | # 64 KB of external RAM, starting after internal RAM (ATmega128!), 79 | # only used for heap (malloc()). 80 | #EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff 81 | 82 | EXTMEMOPTS = 83 | 84 | #LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref 85 | LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) 86 | 87 | 88 | # Programming support using avrdude. Settings and variables. 89 | 90 | AVRDUDE_PROGRAMMER = usbasp 91 | #AVRDUDE_PROGRAMMER = stk500 92 | #AVRDUDE_PORT = /dev/ttyUSB0 93 | 94 | AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex 95 | #AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep 96 | 97 | 98 | # Uncomment the following if you want avrdude's erase cycle counter. 99 | # Note that this counter needs to be initialized first using -Yn, 100 | # see avrdude manual. 101 | #AVRDUDE_ERASE_COUNTER = -y 102 | 103 | # Uncomment the following if you do /not/ wish a verification to be 104 | # performed after programming the device. 105 | #AVRDUDE_NO_VERIFY = -V 106 | 107 | # Increase verbosity level. Please use this when submitting bug 108 | # reports about avrdude. See 109 | # to submit bug reports. 110 | #AVRDUDE_VERBOSE = -v -v 111 | 112 | #AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) 113 | AVRDUDE_BASIC = -p $(MCU) -c $(AVRDUDE_PROGRAMMER) 114 | AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) -E noreset 115 | 116 | 117 | CC = avr-gcc 118 | OBJCOPY = avr-objcopy 119 | OBJDUMP = avr-objdump 120 | SIZE = avr-size 121 | NM = avr-nm 122 | AVRDUDE = avrdude 123 | REMOVE = rm -f 124 | MV = mv -f 125 | 126 | # Define all object files. 127 | OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) 128 | 129 | # Define all listing files. 130 | LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) 131 | 132 | # Combine all necessary flags and optional flags. 133 | # Add target processor to flags. 134 | ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) 135 | ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) 136 | 137 | 138 | # Default target. 139 | all: build 140 | 141 | build: elf hex eep 142 | 143 | elf: $(TARGET).elf 144 | hex: $(TARGET).hex 145 | eep: $(TARGET).eep 146 | lss: $(TARGET).lss 147 | sym: $(TARGET).sym 148 | 149 | 150 | # Program the device. 151 | program: $(TARGET).hex $(TARGET).eep 152 | $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) 153 | 154 | 155 | 156 | 157 | # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. 158 | COFFCONVERT=$(OBJCOPY) --debugging \ 159 | --change-section-address .data-0x800000 \ 160 | --change-section-address .bss-0x800000 \ 161 | --change-section-address .noinit-0x800000 \ 162 | --change-section-address .eeprom-0x810000 163 | 164 | 165 | coff: $(TARGET).elf 166 | $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof 167 | 168 | 169 | extcoff: $(TARGET).elf 170 | $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof 171 | 172 | 173 | .SUFFIXES: .elf .hex .eep .lss .sym 174 | 175 | .elf.hex: 176 | $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ 177 | 178 | .elf.eep: 179 | -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ 180 | --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ 181 | 182 | # Create extended listing file from ELF output file. 183 | .elf.lss: 184 | $(OBJDUMP) -h -S $< > $@ 185 | 186 | # Create a symbol table from ELF output file. 187 | .elf.sym: 188 | $(NM) -n $< > $@ 189 | 190 | 191 | 192 | # Link: create ELF output file from object files. 193 | $(TARGET).elf: $(OBJ) 194 | $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) 195 | 196 | 197 | # Compile: create object files from C source files. 198 | .c.o: 199 | $(CC) -c $(ALL_CFLAGS) $< -o $@ 200 | 201 | 202 | # Compile: create assembler files from C source files. 203 | .c.s: 204 | $(CC) -S $(ALL_CFLAGS) $< -o $@ 205 | 206 | 207 | # Assemble: create object files from assembler source files. 208 | .S.o: 209 | $(CC) -c $(ALL_ASFLAGS) $< -o $@ 210 | 211 | 212 | 213 | # Target: clean project. 214 | clean: 215 | $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ 216 | $(TARGET).map $(TARGET).sym $(TARGET).lss \ 217 | $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) 218 | 219 | depend: 220 | if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ 221 | then \ 222 | sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ 223 | $(MAKEFILE).$$$$ && \ 224 | $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ 225 | fi 226 | echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ 227 | >> $(MAKEFILE); \ 228 | $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) 229 | 230 | .PHONY: all build elf hex eep lss sym program coff extcoff clean depend 231 | 232 | 233 | -------------------------------------------------------------------------------- /mdb_billv.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "mdb.h" 3 | #include "mdb_billv.h" 4 | 5 | #include "uart.h" 6 | #include "utils.h" 7 | 8 | void mdb_billv_handler() 9 | { 10 | unsigned char buf[MDB_BLOCK_LIMIT+1]; 11 | unsigned char len=MDB_BLOCK_LIMIT+1; 12 | char rev, ch, bill_status, bill_type; 13 | char tmp[32]; 14 | 15 | static unsigned char last_status[16]; 16 | static unsigned char last_len; 17 | unsigned char same_to_last; 18 | 19 | mdb_uart_flush(); 20 | 21 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_POLL, NULL, 0); 22 | rev = mdb_tick(buf, &len, 5000); 23 | 24 | if (rev == MDB_TICK_OK) { 25 | same_to_last = 1; 26 | if (len == last_len) { 27 | for (unsigned char i=0; i\n"); 53 | } else { 54 | mdb_ack(); 55 | 56 | if (!same_to_last) { 57 | uart_print("<"); 58 | } 59 | 60 | for (unsigned char i=0; i> 4; 66 | bill_type = mdb_setup_info.type[ch & 0x0f]; 67 | 68 | sprintf(tmp, "b_status:0x%02x,$:%d,", bill_status, bill_type); 69 | uart_print(tmp); 70 | } else { /* a status byte */ 71 | switch (ch) 72 | { 73 | case MDB_BILLV_POLL_STATUS_DEFECTIVE_MOTOR: 74 | if (!same_to_last) uart_print("billv_motor_error,"); 75 | break; 76 | case MDB_BILLV_POLL_STATUS_SENSOR_PROBLEM: 77 | if (!same_to_last) uart_print("billv_sensor_error,"); 78 | break; 79 | case MDB_BILLV_POLL_STATUS_BUSY: 80 | if (!same_to_last) uart_print("billv_busy,"); 81 | break; 82 | case MDB_BILLV_POLL_STATUS_ROM_ERROR: 83 | if (!same_to_last) uart_print("billv_rom_error,"); 84 | break; 85 | case MDB_BILLV_POLL_STATUS_JAMMED: 86 | if (!same_to_last) uart_print("billv_jam,"); 87 | break; 88 | case MDB_BILLV_POLL_STATUS_JUST_RESET: 89 | if (!same_to_last) uart_print("billv_justreset,"); 90 | mdb_billv_init(); 91 | break; 92 | case MDB_BILLV_POLL_STATUS_BILL_REMOVED: 93 | if (!same_to_last) uart_print("billv_bill_removed,"); 94 | break; 95 | case MDB_BILLV_POLL_STATUS_NO_CASHBOX: 96 | if (!same_to_last) uart_print("billv_no_cashbox,"); 97 | break; 98 | case MDB_BILLV_POLL_STATUS_DISABLED: 99 | if (!same_to_last) uart_print("billv_disabled,"); 100 | break; 101 | case MDB_BILLV_POLL_STATUS_INVALID_ESCROW: 102 | if (!same_to_last) uart_print("billv_invalid_escrow,"); 103 | break; 104 | case MDB_BILLV_POLL_STATUS_BILL_REJECTED: 105 | if (!same_to_last) uart_print("billv_rejected,"); 106 | break; 107 | case MDB_BILLV_POLL_STATUS_STACKED_REMOVE: 108 | if (!same_to_last) uart_print("billv_stacked_remove,"); 109 | break; 110 | default: 111 | sprintf(tmp, "0x%02x,", tmp[i]); 112 | uart_print(tmp); 113 | break; 114 | } 115 | } 116 | } 117 | 118 | if (!same_to_last) { 119 | uart_print(">\n"); 120 | } 121 | } 122 | 123 | } else { 124 | mdb_billv_init(); 125 | } 126 | 127 | // printf("\n"); 128 | } 129 | 130 | void mdb_billv_enable(void) 131 | { 132 | unsigned char buf[16]; 133 | unsigned char len; 134 | unsigned char rev; 135 | 136 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_RESET, NULL, 0); 137 | // mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_RESET, "\xff\xff\xff\xff", 4); 138 | rev = mdb_tick(buf, &len, 5000); 139 | } 140 | 141 | void mdb_billv_disable(void) 142 | { 143 | unsigned char buf[16]; 144 | unsigned char len; 145 | unsigned char rev; 146 | 147 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_TYPE, "\x00\x00\x00\x00", 4); 148 | rev = mdb_tick(buf, &len, 5000); 149 | } 150 | 151 | void mdb_billv_escrow(unsigned char stack) 152 | { 153 | unsigned char buf[16]; 154 | unsigned char len; 155 | unsigned char rev; 156 | 157 | if (stack) { 158 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_ESCROW, "\x0f", 1); 159 | } else { 160 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_ESCROW, "\x00", 1); 161 | } 162 | rev = mdb_tick(buf, &len, 50000); 163 | } 164 | 165 | void mdb_billv_init() 166 | { 167 | unsigned char buf[MDB_BLOCK_LIMIT+1]; 168 | unsigned char len=MDB_BLOCK_LIMIT+1; 169 | char rev; 170 | 171 | // printf("reset..."); 172 | mdb_uart_flush(); 173 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_RESET, NULL, 0); 174 | rev = mdb_tick(buf, &len, 5000); 175 | if (rev == MDB_TICK_OK && buf[0] == MDB_RESP_ACK) { 176 | // printf("done\n"); 177 | } else { 178 | // printf("no ack\n"); 179 | return; 180 | } 181 | 182 | // printf("polling.."); 183 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_POLL, NULL, 0); 184 | rev = mdb_tick(buf, &len, 5000); 185 | if (buf[0] != MDB_RESP_ACK) { 186 | mdb_ack(); 187 | } 188 | // printf("tick rev: %d, len: %d\n", rev, len); 189 | // mdb_debug_data(buf, len); 190 | 191 | // printf("setup info..\n"); 192 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_SETUP, NULL, 0); 193 | rev = mdb_tick(buf, &len, 5000); 194 | // printf("tick rev: %d, len: %d\n", rev, len); 195 | mdb_billv_parse_setupinfo(buf, len); 196 | mdb_ack(); 197 | // mdb_debug_data(buf, len); 198 | 199 | // printf("setting securit..\n"); 200 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_SECUR, "\xff\xff", 2); 201 | rev = mdb_tick(buf, &len, 5000); 202 | // printf("tick rev: %d, len: %d\n", rev, len); 203 | // mdb_debug_data(buf, len); 204 | 205 | // printf("setting type..\n"); 206 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_TYPE, "\xff\xff\xff\xff", 4); 207 | rev = mdb_tick(buf, &len, 5000); 208 | // printf("tick rev: %d, len: %d\n", rev, len); 209 | // mdb_debug_data(buf, len); 210 | 211 | // printf("\n"); 212 | } 213 | 214 | unsigned char mdb_billv_parse_setupinfo(unsigned char *buf, unsigned char len) 215 | { 216 | unsigned char rev = 0; 217 | 218 | if (len != 27) { /* the magic no defined by MDB spec */ 219 | // printf("setup info len failed\n"); 220 | rev = -1; 221 | } else { 222 | memcpy(&mdb_setup_info, buf, len); 223 | } 224 | 225 | return rev; 226 | } 227 | 228 | void mdb_billv_stacker_info() 229 | { 230 | unsigned char buf[16], tmp[16]; 231 | unsigned char len=0; 232 | char rev; 233 | 234 | mdb_send(MDB_ADDR_BILLV, MDB_CMD_BILLV_STACKER, NULL, 0); 235 | rev = mdb_tick(buf, &len, 5000); 236 | // printf("tick rev: %d, len: %d\n", rev, len); 237 | mdb_ack(); 238 | // mdb_debug_data(buf, len); 239 | 240 | sprintf(tmp, "<%d%d,>\n", buf[0], buf[1]); 241 | uart_print(tmp); 242 | } 243 | 244 | void mdb_billv_info() 245 | { 246 | unsigned char tmp[32]; 247 | 248 | uart_print("<"); 249 | 250 | sprintf(tmp, "level:%u,", mdb_setup_info.level); 251 | uart_print(tmp); 252 | 253 | sprintf(tmp, "country:0x%x,", conv_order_short(mdb_setup_info.country)); 254 | uart_print(tmp); 255 | 256 | sprintf(tmp, "scaling_factor:%u,", conv_order_short(mdb_setup_info.scaling_factor)); 257 | uart_print(tmp); 258 | 259 | sprintf(tmp, "decimal_place:%u,", mdb_setup_info.decimal_place); 260 | uart_print(tmp); 261 | 262 | sprintf(tmp, "stacker_capacity:%u,", 263 | conv_order_short(mdb_setup_info.stacker_capacity)); 264 | uart_print(tmp); 265 | 266 | sprintf(tmp, "security_level:0x%x,", 267 | conv_order_short(mdb_setup_info.security_level)); 268 | uart_print(tmp); 269 | 270 | sprintf(tmp, "escrow:%u,", mdb_setup_info.escrow); 271 | uart_print(tmp); 272 | 273 | uart_print("support:"); 274 | for (unsigned char i=0; i<16; i++) 275 | { 276 | if (mdb_setup_info.type[i] != 0) 277 | { 278 | sprintf(tmp, "%u|", mdb_setup_info.type[i]); 279 | uart_print(tmp); 280 | } 281 | } 282 | 283 | 284 | uart_print(">\n"); 285 | } 286 | --------------------------------------------------------------------------------