← ST-Computer 11 / 1991

Sony-GerÀte selbstgesteuert: Der SIRCS-Bus

Hardware

Viele GerĂ€te werden heutzutage nicht nur mit einer Fernbedienung geliefert, einige besitzen sogar einen Fernbedienungseingang. Der Control-S-Bus von Sony (auch SIRCS genannt) ist ein TTL-kompatibler Bus, d.h. er arbeitet mit Signalen von 0 und 5 Volt. Damit ist er sehr einfach mit einem Computer steuerbar. Dieser Artikel beschreibt das Format eines Control-S-Befehls samt zugehöriger Steuer-Software. Damit lĂ€ĂŸt sich der ST z.B. als Schnittcomputer oder als komfortabler Timer fĂŒr die nĂ€chsten 100 Jahre benutzen, obwohl das GerĂ€t dann wahrscheinlich veraltet ist.

Kommunikation zwischen Sony und Atari

Dabei ist der Hardware-Aufwand minimal, mit weniger als 10 Mark ist man dabei. NatĂŒrlich ist bei solchen Basteleien entsprechend vorsichtig vorzugehen, und wir können weder garantieren, daß das vorgestellte Programm mit Ihrem GerĂ€t zusammenarbeitet, noch ob es Rechner oder Videorekorder beschĂ€digt!

Allerdings lĂ€uft bei mir die Schaltung einwandfrei, und ein Widerstand sorgt dafĂŒr, daß z.B. bei Kurzschluß nach dem Ohmschen Gesetz der Port im ST mit nur

I = U/R = 5V / 5600 Ω = 0.9 mA

belastet wird. Damit geht’s schon an die Hardware. Auf der Seite des zu steuernden GerĂ€tes braucht man nur einen 3.5mm-Mono-Klinkenstecker, auf der Seite des ST einen 25pol. Sub-D-Stecker, sofern man das GerĂ€t mit dem Centronicsport steuern möchte.

NatĂŒrlich kann man dazu auch irgendeinen anderen Port benutzen, in der Steuer-Software mĂŒssen dann nur die beiden Routinen set_one und set_zero am Ende des Assemblerlistings geĂ€ndert werden.

Als Steuerleitung kann ein beliebiges zweipoliges Kabel benutzt werden, besser ist allerdings ein abgeschirmtes Monokabel. Die Abschirmung wird dabei an eine der Masseleitungen am Sub-D-Stecker gelötet (Anschluß 18-25). Der 5.6KΩ-Widerstand wird an Daten-Bit 0 des Drucker-Ports gelegt (Anschluß 2). Anschließend muß die innere Leitung des Kabels an das andere Ende des Widerstandes gelötet werden. Damit sind die Arbeiten auf der Rechnerseite des Kabels beendet. Am anderen Ende wird das Innere des Kabels an den inneren Anschluß des Klinkensteckers gelötet, die Abschirmung kommt an den Ă€ußeren Anschluß des Steckers. Und das war’s.

Dieser Klinkenstecker kommt in die CONTROL-S-IN-Buchse des zu steuernden GerÀtes, NICHT an die CONTROL-S-OUT-Buchse!

Da im GerĂ€t der CONTROL-S-Eingang und der Fernbedienungssensor auf eine Leitung verodert sind, ist die Fernbedienung wirkungslos, wenn der Drucker-Port dauerhaft auf High geschaltet wird! Aber nach dem Reset schaltet der ST den Drucker-Port ohnehin auf Low. Und Schaden wĂŒrde das GerĂ€t dabei sowieso nicht nehmen (hat es bei mir zumindest nicht getan), also keine Bange.

Wie geht’s?

Hier nun eine Beschreibung des Sony-Control-S-Formats. Keine Angst, wenn nicht alles verstanden wird, das Programm lĂ€uft auch so. Die Routine send_sony() ĂŒbernimmt die ganze Arbeit und kann zu eigenen Programmen dazugebunden werden. In Tabelle 1 stehen die GerĂ€tecodes und in Tabelle 2 die mir bekannten Befehle. Ein Teil dieser Befehle stammt aus den Sony-Control-S-Protocol-Specifications von Scott Coleman, den Rest habe ich mit einem Oszilloskop selbst herausgefunden. Wenn also der eine oder andere Befehl hier nicht aufgefĂŒhrt ist, hilft nur: ausprobieren. Auch kann ein Befehl auf diesem oder jenem GerĂ€t eine andere Bedeutung haben oder ĂŒberhaupt nicht funktionieren. Denn sowohl Scott Coleman als auch ich hatten keine offizielle Sony-Dokumentation zur VerfĂŒgung, alle Angaben beruhen auf experimentell ermittelten Werten.

Aber jetzt zur Sache. Ein Befehlswort besteht dabei aus 12 Bits, wovon die ersten 7 Bits den eigentliche Befehl darstellen und die restlichen 5 Bits das GerĂ€t angeben, fĂŒr das der Befehl bestimmt ist. Damit können 128 Befehle an 32 GerĂ€te verschickt werden, wobei ja Befehlscodes fĂŒr verschiedene GerĂ€te auch unterschiedliche Bedeutung haben können. Nun werden diese 12 Bits aber nicht einfach so verschickt, sondern werden codiert. ZunĂ€chst geht das Signal fĂŒr 2.4 ms auf High, dann fĂŒr 0.6 ms auf Low. Das war sozusagen das „Start-Bit“. Jetzt werden die 12 Bits des Befehls-/GerĂ€tecodes gesendet, jeweils das niederwertigste Bit zuerst. Ein Bit ist dabei folgendermaßen codiert:

0: 0.6ms High, 0.6ms Low 1: 1,2ms High, 0.6ms Low TV 1 VTR1 2 Betamax VTR2 4 Betamax VTR2 7 Video 8 VTR3 11 VHS

Tabelle 1: GerÀtecodes

Damit wird sichergestellt, daß der Code gleichstromfrei ist, das Signal muß also nach spĂ€testens 1,2ms seinen Zustand Ă€ndern.

Bevor der Befehlscode noch einmal bzw. ein anderer Befehlscode gesendet werden darf, muß zunĂ€chst gewartet werden, bis 45ms vergangen sind, seit das Signal beim Start-Bit zum ersten Mal auf High gegangen ist.

Damit ein Code vom GerĂ€t erkannt wird, muß mindestens 3mal das gleiche Befehlswort erkannt werden, sonst wird von einem Übertragungsfehler ausgegangen.

Die Software

Der Routine send_sony() wird nur ĂŒbergeben, welches GerĂ€t welchen Befehl wie oft erhalten soll. Das Beispielprogramm steuert die wichtigsten Funktionen eines Videorekorders und ist als Accessory oder als Programm lauffĂ€hig. Unter Verwendung der Projektdatei und des Turbo-C Compilers 2.0 sollte es kein Problem sein, das Programm zum Laufen zu bringen. Gegebenenfalls muß nur die Zeile

#define VTR VTR3

im SONY.C-Listing auf das entsprechende System angepaßt werden.

Literatur:
Sony-Control-S-Protocol-Specifications by Scott Coleman

   
0 Taste 1
1 Taste 2
2 Taste 3
3 Taste 4
4 Taste 5
5 Taste 6
6 Taste 7
7 Taste 8
8 Taste 9
9 Taste 10/Taste 0
10 Taste -/—-, Taste 11, Taste *
11 Taste 12, Taste CH/Enter/#
12 Taste 13, Taste 1-
13 Taste 14, Taste 2-
16 Programm +
17 Programm -
18 LautstÀrke +
19 LautstÀrke -
20 Zeitraffer X 2 / X3
21 Power
22 Eject
23 Audio Monitor (L-CH/R-CH/Stereo)
24 Stop
25 Pause
26 Play
27 Rewind
28 FF
29 Record
32 Freeze Frame >
34 X 1/10 play
35 X 1/5 play
38 High Double Speed ( X7 ~ X15X )
40 Review (RĂŒcklauf mit Bild)
41 Cue (Vorlauf mit Bild)
42 TV/VTR
45 VTR from TV (ANT-VTR)
46 Power on
47 Power off
48 Einzelbild rĂŒckwĂ€rts/langsame RĂŒckwĂ€rtswiedergabe
49 Einzelbild vorwÀrts/langsame VorwÀrtswiedergabe
51 X 1
58 ZurĂŒckspulen, dann Play
60 aux
61 Zeitlupe +
62 Zeitlupe -
64 Function Memory
66 Cursor auf
67 Cursor ab
70 ZĂ€hler Reset
71 Counter Memory on/off
72 Index write
73 Index erase
74 Shuttle >
75 Shuttle <
77 Menu
78 TV/VTR (ANT-TV)
79 Input Select
81 Execute
83 index (scan)
85 Edit Monitor
88 Rec Mode (SP/LP)
89 Tape return
90 Data Screen / Display on/off
91 Open/Close
92 Timer on screen
97 Cursor rechts
98 Cursor links
99 Timer löschen
100 Timer check
104 Audio Insert
105 Video Insert
106 edit play (Assemble)
107 mark
108 Start
110 PiP off
111 PiP shift
116 TV scan
119 Picture in picture (PiP) on

Tabelle 2: Befehlscodes

SONY.PRG = TCSTART.O SONY.C SEND.S TCSTDLIB.LXB TCGEMLIB LIB #define DIALOG 0 /* TREE */ #define POWER 1 /* OBJECT in TREE #0 */ #define PAUSE 3 /* OBJECT in TREE #0 */ #define PLAY 4 /* OBJECT in TREE #0 */ #define REC 5 /* OBJECT in TREE #0 */ #define REW 6 /* OBJECT in TREE #0 */ #define STOP 7 /* OBJECT in TREE #0 */ #define FF 8 /* OBJECT in TREE #0 */ #define EJECT 9 /* OBJECT in TREE #0 */ #define FERTIG 10 /* OBJECT in TREE #0 */ #define PRGUP 11 /* OBJECT in TREE #0 */ #define PRGDOWN 12 /* OBJECT in TREE #0 */ OBJECT rs_object[] = { -1, 1, 13, G_BOX, NONE, OUTLINED, 0x2H00L, 0,0, 34,12, 2, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"POWER", 2,1, 8,1, 3, -1, -1, G_STRING, NONE, NORMAL, (long)"SIRCS-Fernbedienung", 13,1, 19,1, 4, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"PAUSE", 3,4, 8,1, 5, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"PLAY", 13,4, 8,1, 6, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"REC", 23,4, 8,1, 7, -1, -1, G_BUTTON, TOUCHEXIT, NORMAL, (long)"REW", 3,6, 8,1, 8, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"STOP", 13,6, 8,1, 9, -1, -1, G_BUTTON, TOUCHEXIT, NORMAL, (long)"FF", 23,6, 8,1, 10, -1, -1, G_BUTTON, 0x5, NORMAL, (long)"EJECT", 3,8, 8,1, 11, -1, -1, G_BUTTON, 0x7, NORMAL, (long)"FERTIG", 13,10, 8,1, 12, -1, -1, G_BUTTON, TOUCHEXIT, NORMAL, (long)"+", 29,8. 2,1, 13, -1, -1, G_BUTTON, TOUCHEXXT, NORMAL, (long)"-", 29,10, 2,1, 0, -1, -1, G_STRING, LASTOB, NORMAL, (long)"Programm ", 19,8, 9,1); LONG rs_trindex[] = { 0L}; struct foobar { WORD dummy; WORD *image, } rs_imdope[] = { 0}; #define NUM_OBS 14 #define NUM_TREE 1 * Senden eines Befehls an ein GerĂ€t mit * Sony SIRCS (Control-S) Anschluß * von Oliver Scholz * (c) MAXON Computer 1991 MFP equ $FFFFFA01 INT_ENA_A equ MFP+$6 INT_PEND_A equ MFP+$A INT_MASK_A equ MFP+$12 TA_CTRL equ MFP+$18 TA_DATA equ MFP+$1E SOUND equ $FFFF8800 * C-Deklaration: * VOID send_sony(WORD device, WORD command, * WORD times) * .globl send_sony send_sony: move d0,device move d1,command move d2,times movem.l d2-d7/a2-a6,-(sp) send_loop: tst times ;entsprechend oft senden beq done pea do_send move #38,-(sp) ;im Supervisormodus trap #14 ;ausfĂŒhren addq.l #6,sp sub #1,times bra send_loop done: movem.l (sp)+,d2-d7/a2-a6 rts .super do_send: move sr,-(sp) ori #$700,sr ; Interrupts sperren clr.b TA_CTRL ; Timer anhalten bclr.b #5,INT_ENA_A ; Interrupt disablen bclr.b #5,INT_MASK_A ; Interrupt maskieren bset.b #5,INT_ENA_A ; Interrupt enablen move (sp)+,sr ; Interrupts frei! * Sony SIRCS Wort senden clr counter ; ZeitzĂ€hler löschen bsr set_one ; Ausgang auf High bsr wait0_6 ; 2.4 ms warten bsr wait0_6 bsr wait0_6 bsr wait0_6 bsr set_zero ; und auf Low: bsr wait0_6 ; das war der Startschuß move command,d0 ; Kommando senden move #6,d1 ; 7 Bits bsr cmd_loop move device,d0 ; Zielgeratecode move #4,d1 ; senden (5 Bits) bsr cmd_loop fill: bsr wait0_6 cmp #75,counter ; auffĂŒllen, bis 45ms blt fill rts * Bits an GerĂ€t senden * Anzahl der Bits minus 1 in D1.w * Die Bits selbst in D0.w * Leitung fĂŒr jedes 1-Bit 1.2ms auf High, * fĂŒr Null-Bits nur 0.6ms auf High * danach 0.6ms auf Low cmd_loop: bsr set_one ; Leitung auf high bsr wait0_6 btst #0,d0 ; unterstes Bit beq cmd_zero ; Bit ist Null bsr wait0_6 cmd_zero: bsr set_zero bsr wait0_6 lsr #1,d0 dbf d1,cmd_loop rts * 0.6 ms warten wait0_6: move.b #$DF,INT_PEND_A ; Flag löschen move.b #92,TA_DATA ; Timer setzen move.b #3,TA_CTRL ; und einschalten wait: btst.b #5,INT_PEND_A ; Warten, bis Flag beq wait ; gesetzt clr.b TA_CTRL ; Timer wieder stop add #1,counter ; bisher gewartete rts ; Intervalle: erhöhen * Leitung auf eins setzen set_one: move.b #$F,SOUND ; Port B schreiben move.b #1,SOUND+2 rts set_zero: move.b #$F,SOUND move.b #0,SOUND+2 rts .bss counter: ds.w 1 device: ds.w 1 command: ds.w 1 times: ds.w 1 /* * Control-S-Steuerprogramm fĂŒr Videorekorder * von Oliver Scholz * (c) 1991 MAXON Computer 1991 */ #include "portab.h" #include "aes.h" #lnclude "stdlib.h" #include "sony.h" #include "sony.rsh" #define TV 1 #define VTR1 2 #define VTR2 7 #define VTR3 11 /* VTR1 fĂŒr Betamax */ /* VTR2 fĂŒr Video 8 */ /* VTR3 fĂŒr VHS */ #define VTR VTR3 #define TRUE 1 #define FALSE 0 VOID send_sony(WORD device, WORD command, WORD times); OBJECT *get_traddr(WORD tree_index), VOID do_dialog(OBJECT *dial); VOID redo_obj(OBJECT *tree, WORD index); extern _app; VOID main(VOID) { OBJECT *dialog; WORD i,dummy; WORD event; WORD msgbuff[8]; WORD ap_id, mn_id; /* Programm initialisieren */ ap_id = appl_init(); if(ap_id == -1) exit(-1); /* Dialogadresse berechnen */ for (i=0; 1<NUM_OBS; i++) rsrc_obfix(rs_object,i); dialog=get_traddr(DIALOG); if(_app) { /* Applikation */ graf_mouse(ARROW,0L); do_dialog(dialog); } else { /* Accessory */ mn_id = menu_register( ap_id," Fernbedienung" ); /* keine Touchexit Knöpfe.. */ dialog[REW].ob_flags=SELECTABLE|EXIT; dialog[FF].ob_flags=SELECTABLE|EXIT; dialog[PRGUP].ob_flags=SELECTABLE|EXIT; dialog[PRGDOWN].ob_flags=SELECTABLE|EXIT; do { event = evnt_multi(MU_MESAG, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, msgbuff, 0, 0, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy ); if(event & MU_MESAG) if((msgbuff[0] == AC_DPEN) && (msgbuff[4] == mn_id)) do_dialog(dialog); } while (TRUE); } appl_exit(); exit (0); } /* Adresse eines Baumes ermitteln */ OBJECT *get_traddr (WORD tree_index) { WORD i,j; for (i=0,j=0; i<=tree_index; i++) while (rs_object[j++] ob_next!=-1); return(&rs_object[—-j]); } VOID do_dialog(OBJECT *dial) { WORD cx,cy,cw,ch; WORD xflag, exitobj; form_center(dial,&cx,&cy,&cw,&ch); form_dial(FMD_START,cx,cy,cw,ch,cx,cy,cw,ch); xflag = FALSE; objc_draw(dial,ROOT,MAX_DEPTH,cx,cy,cw,ch); do { exitobj = form_do(dial, 0) & 0x7fff; dial[exitobj],ob_state &= ~SELECTED; switch(exitobj) { case FERTIG: xflag = TRUE; break; case POWER: send_sony(VTR,21,3); break; case PAUSE: send_sony(VTR,25,3); break; case PLAY: send_sony(VTR,26,3); break; case REC: send_sony(VTR, 29, 3); break; case REW: send_sony(VTR,27,3); break; case STOP: send_sony(VTR,24,3); break; case EJECT: send_sony(VTR,22,3); break; case FF: send_sony(VTR,28,3); break; case PRGUP: send_sony(VTR,16,3); break; case PRGDOWN: send_sony(VTR,17,3); break; } redo_obj(dial,exitobj); } while(!xflag); form_dial (FMD_FINISH,cx,cy,cw,ch,cx,cy, cw,ch); } VOID redo_obj(OBJECT *tree, WORD index) { WORD x, y, w, h; objc_offset(tree,index,&x,&y); w = tree[index].ob_width, h = tree[index].ob_height; objc_draw (tree, ROOT,MAX_DEPTH,x,y,w,h); }
Oliver Scholz